- The API, at
…/v1: routes, fields, validation. A change that needs a client change is listed here. - Processing builds, which do the transcription, translation, dubbing and packaging. A project
runs on the build in its
buildVersionuntil you change it, so a new build never changes an existing project.GET /build-versionslists them; your default is inGET /whoami.
Known issues
Each issue names the builds it affects and the build that fixes it. The pages that describe the affected feature carry the same warning, and lose it when it is fixed.API
Your own bucket: storage connections
- A project can keep its input and output folders in a bucket of your own, on AWS S3 or an
S3-compatible store (Cloudflare R2, Wasabi, MinIO). Enter the bucket and an access key pair
once as a storage connection of your account (
POST /account/storage-connections; the bucket is listed with the keys before anything is saved), then name it on a project:storage: {connectionId, inputPrefix?, outputPrefix?}on create orPATCH. The project’s files are listed from, downloaded from and deleted in your bucket; the service’s own bookkeeping stays in SyncWords’ storage.PATCH /account/settingssets a default connection for projects created withoutstorage. Your own bucket. storage.connectionon the project resource: null for SyncWords’ storage, else the connection’s id, name, bucket and endpoint. Existing projects readnull.- A project on your bucket is a folder project: a feed source or a feed output with a
connection is refused (
storage_connection_folder_only). Needs build0.9.0-alpha1-2026-10-20T14-10Z-3f05aaor later, the default from today.
Build 3f05aa; a recovered AI timeout no longer fails a file
Processing build
0.9.0-alpha1-2026-10-20T14-10Z-3f05aa is the new default, and every project
was moved to it. Its config is the same as …-ed2c99’s, so no client change is needed.- A translation request that timed out once and was retried no longer fails the file. The engine’s retry succeeded, but the first attempt’s error line failed the file at the end of its run, hours of processing with it. Fixed in this build.
- Builds before
0.9.0-alpha1-2026-10-20T14-10Z-3f05aaare no longer listed byGET /build-versionsor accepted inbuildVersion.
Auto-stopped projects start on a new file; startOnNewFiles
- A project that stopped itself after its last file starts again on its own when a new file
lands in its input folder, within a minute, however it got there: the AWS CLI, an SDK, or a
one-
PUTupload. Until now only an API upload in parts did this, and a file copied in waited aspendingforPOST /projects/{id}/start. A project stopped withPOST …/stop, created withautoStart: falseand never started, stopped after its service failed, or inerrorstill waits. Callingstartafter an upload stays harmless. startOnNewFiles, a new project field (defaulttrue), set on create and changed withPATCH:falsekeeps a stopped project stopped whatever arrives, including a completed API upload, untilPOST …/start. Retrying a file still starts it. Existing projects readtrue, so nothing changes for a client that does not send it. Starting again on a new file.
File counts on the project
- The project resource carries
files: how many input files arepending,processing,doneandfailed, withtotalandcountedAt, the same counts asmetaofGET …/files. Kept on the project, soGET /projectsshows every project’s progress in one call; counted once a minute for a project with a service or changed in the last day, and at once after an upload completes, a file is deleted or retried, or its files are listed.nulluntil the first count. Projects. GET /projects?status=completedlists the stopped projects whose files are all finished (doneorfailed) with at least one done, and?status=failedthose inerrorplus the stopped ones whose files all failed, as last counted.
Upload a file in one PUT
POST /projects/{id}/uploadsalso answersurl: a presigned S3PUTfor the whole file, for a file of 5 GB or under that is not replacing one already ininput/.PUTthe file to it and it is ininput/: no parts, no complete call.urlExpiresAtsays when the URL stops working. The multipart fields are as they were, so a client that sends parts needs no change. One PUT. The quick start uploads this way now.
Build ed2c99; feeds through redirects
Processing build
0.9.0-alpha1-2026-10-12T15-21Z-ed2c99 is the new default, and every project
was moved to it. Its config is the same as …-dae007’s, so no client change is needed.- A feed that redirects is accepted. Saving a feed URL and
GET …/source-feedfollow up to 5 redirects, as the project does, and refuse only a redirect from HTTPS to HTTP (The feed answered HTTP 301, a redirect to http://…, which is not followed: …). Before, any redirect was refused. Feeds. - Files are no longer processed in batches. The next file starts as soon as one finishes, instead of after the whole batch.
- A file being processed when its project stops is cleaned up and processed again from the start on the next run.
- Builds before
0.9.0-alpha1-2026-10-12T15-21Z-ed2c99are no longer listed byGET /build-versionsor accepted inbuildVersion.
Build dae007; dub tracks and the input's audio
Breaking: a video or audio file’s tracks changed shape, with processing build
0.9.0-alpha1-2026-10-09T16-39Z-dae007, the new default. Every existing project was moved to
the new shape and onto this build, so nothing stops working; a client that sends or reads
config needs the changes below.audioTracksis gone fromVideoFileandAudioFile.useOriginalTracks: truecopies the input file’s own audio as it is, with its own language tag, title and default flag, and always comes first;dubTrackslists the dubs after it, each{language, codec, title}.language: "original"and a track’sdefaultare gone. With neither field, a video has no sound. Audio tracks.- A dub can no longer be the track a player picks first in a file that also carries the
input’s audio: dub tracks have no default flag, so a player opens the file on the input’s
audio. For a file that plays the dub when it opens, leave
useOriginalTracksout. subtitleTracksis nowsubTracks, and its entries have no@type:language,options,subtitleCodec. Their errors are under…/subTracks/{n}/….- Embedded CEA-608 captions are gone:
StreamingEmbedded608can no longer be configured. Use subtitle tracks or subtitle files. - An
AudioFileholds exactly one audio track:useOriginalTracks: trueor onedubTracksentry. A file with neither, with both or with two dubs is refused with422, and so is the input’s audio in anmp3orwavfile: it is copied as it is, so useipod(.m4a) ormatroska. AudioFile. - Existing projects: dubs became
dubTracksin their order, withoutdefault; anoriginaltrack becameuseOriginalTracks: true, without its title (the input’s own is kept); embedded captions were removed. A video that had a dub as its default track and the original beside it now opens on the original. - The
unused_translationandunused_dubmessages speak of dub tracks. - Builds before
0.9.0-alpha1-2026-10-09T16-39Z-dae007are no longer listed byGET /build-versionsor accepted inbuildVersion.
Build 3cf17c; files without error counts
With processing build
0.9.0-alpha1-2026-10-09T14-08Z-3cf17c, the new default:errorsandwarningsare gone fromGET /projects/{id}/filesand from thefile.donewebhook. They counted log lines, which said little about whether a dub was usable. From this build a file whose engines reported an error (a line the voice could not say, a translation that failed) isfailedinstead ofdonewith gaps: seefailureCode, and retry it.GET /projects/{id}/files/{name}/metadocuments what a run records:hash,inputVersion,startedAt,finishedAt,durationMs,dubbingMs.- Subtitles mark a change of speaker with
>>, in subtitle files and in a video’s subtitle tracks, unless the entry’soptionssay otherwise. Speaker changes.
Tokens from this API
- Your account’s dictionaries and glossaries.
transcription.dictionaryandpostprocessingDictionarytake a dictionary of your SyncWords Live account by id or name, and a translation engine’sglossarya glossary’s id, beside the inline forms. A field left out takes your account’s default for the language;nulltakes none. A project that leaves them out starts with your defaults applied the next time it starts. See Your account’s dictionaries. POST /token/createexchanges your API key pair for a token here, so a client needs one host. It answers the Live API’s fields (access_token,token_type), plusexpires_inwhere tokens expire by age, and a wrong pair is401invalid_credentials. Tokens from the Live API’sPOST /v2/token/createkeep working. There is no refresh or revoke: create a new token when one expires. Authentication.
RSS feeds and feed text translation
With processing build
0.9.0-alpha1-2026-10-07T11-55Z-b1b8d1, the new default:- Two kinds of feed source.
{"@type": "RssSource", "url": "…"}reads an RSS 2.0 feed whose items carry their media as<enclosure>s (a podcast feed), besideMrssSource, which now reads only<media:content>(the item’s own, or the default one of its<media:group>, which earlier builds did not read). Each kind reads only its own element; a project may change between the two kinds. Feeds. - Output feeds follow the source’s kind:
RssOutputfor anRssSource,MrssOutputfor anMrssSource; the other pairing is refused under/config/outputs/{n}/@type. The published feed writes the standard channel and item elements first and everything else after them, and updates the media element’s size and type. POST /source-feeds/checktakessourceType(RssSourceorMrssSource, the latter when left out), and every feed check answerssourceTypeand reasons that name the element the kind reads (no <enclosure>; its media is a <media:content>, which a Media RSS source reads).- A feed item’s file name changed with the build: the second part is now a hash of the media URL alone. A feed project moved onto this build processes every item again.
Project messages
meta.messageson every project: what its config will do that you probably do not mean, each with aseverity, a stablecode, the JSONpathit is about, amessageand itsparams. Nothing is refused for it. The first two codes:unused_translation, a translation no output carries, andunused_dub, a dub no output has an audio track for — both still produced and billed. Messages.
Source feeds are checked
- Saving a feed project checks the feed. A new
sourceMediaURL is fetched and read the way the project reads it. A feed that does not answer2xx(redirects included), is not RSS 2.0, or has items none of which links a media file is refused undererrors["/config/sourceMedia/url"], with the reason. A feed with no items yet is accepted. Media RSS feeds. GET /projects/{id}/source-feedreads the project’s feed now: how many items it has, how many the project downloads, and why each skipped item is skipped.409 project_reads_folderfor a folder project.POST /source-feeds/checkwith{"url": "…"}answers the same before a project exists.
Config: sources and destinations
Breaking: the shape of
config changed, with processing build
0.9.0-alpha1-2026-10-05T14-57Z-bf4a93. Every existing project was moved to the new shape, and
any project on a build before …-4787fb to …-bf4a93, so nothing stops working; a client that
sends or reads config needs the changes below.outputslists destinations, each with itsitems. The files you listed inoutputsgo into theitemsof one{"@type": "S3FolderOutput"}, the project’s output folder; the items themselves are unchanged. Error pointers say where:/config/outputs/0/items/1/nameTemplate. Two items of one destination must not render the same name. Outputs.sourceMediasays where the media comes from:{"@type": "S3FolderSource"}, the input folder, is what a config without one gets, and is stored and shown that way. Inputs.- The project’s
inputfield is gone: the project resource no longer has it, and a body that sends it is refused with422undererrors.input, pointing toconfig.sourceMedia. The codeinput_type_not_availableis gone with it. - Media RSS feeds, in and out.
{"@type": "MrssSource", "url": "https://…"}reads a feed every 30 seconds and processes each item’s media once, as a file of the project. AnMrssOutputper language publishes the feed again with the dubbed files, public atGET /feeds/{projectId}/{language}/feed.xml, its media atGET /feeds/{projectId}/{language}/media/{name}. A feed project takes no uploads (409, new codeproject_reads_feed) and is never stopped for being idle; a feed not written yet answers404with the new codefeed_not_found. Media RSS feeds. - The API fills in every location: a
pathonS3FolderSourceorS3FolderOutput, orpath,mediaPathormediaUrlonMrssOutput, is refused. GET /enums/source-typesandGET /enums/destination-typeslist the new@types;GET /enums/output-typeslists the item kinds, as before.- Builds before
0.9.0-alpha1-2026-10-02T14-37Z-4787fbare no longer listed byGET /build-versionsor accepted inbuildVersion.
Files
usageon every input file: what adonefile was billed for, one entry per caption, translation and dub language, each with the duration it is billed by. Files.
Billing
- A finished file’s captions in the transcription language are billed, beside each translated and each dubbed language. Files finished before this date are not billed for them.
Projects
meta.configLockedon every project:truewhile SyncWords support manages the project’s configuration for you. Meanwhile a change ofconfigorbuildVersionis refused with409and the new codeproject_config_locked;nameanddescriptionstill change, and aconfigequal to the stored one is accepted. Projects.
Voices
"@type": "ElevenLabs"is no longer a voice provider: a project that names it is refused with422. A project saved with it keeps its config and still runs, but a change to its config must pick another provider:MultiVoice, Azure, Google, Amazon Polly, Deepdub or Sarvam.MultiVoicetakes novoices: it gives each speaker a voice from SyncWords’ voices for the translation’s language, and a language without them is refused with422when the project is saved. Avoiceslist is refused, and one saved before is replaced by the language’s voices at the next start. Dubbing.
Input types
- A project has an
input, answered besideconfigon every project resource: where its media comes from.{"type": "folder"}, the input folder, is what every project is and the default whenPOST /projectsleaves it out; it is set on create, andPUT/PATCHrefuse it. - The
mrssinput type — a Media RSS feed the project reads on an interval you choose — is declared in the API and the reference so integrations can be written against its shape, and not available yet: sent,POST /projectsvalidates the body and then answers422with the new codeinput_type_not_available, creating nothing. Inputs.
Webhooks
PATCH /webhooks/{id}changes a webhook’surloreventswithout a new secret;POST /webhooks/{id}/rotate-secretreplaces the secret, the old one signing beside it for 24 hours;POST /webhooks/{id}/deliveries/{eventId}/retrysends a delivery again. New codewebhook_delivery_not_found. Webhooks.GET /webhooks/{id}/deliveriesis paged (page,perPage,links,meta) and takes?status=pending|delivered|failed.datais as before; a page holds 25 by default.- The 10 seconds a delivery has are now counted from the attempt’s start to your server’s status line, however slowly it answers; the body you send back is not waited for.
- Event payloads only grow: fields and event types may be added, none removed or changed.
file.done’shashis documented as what it is: the file’s processing key, the same for every run of a name.- A project whose processing service has read
failedfor 2 hours is stopped (project.stopped,reason: "idle");pod.atis when it first failed.
Second release
- The rate limit is per account: 1000 requests a minute for your organization, whatever other customers send. Until now every caller shared one budget. Limits.
POST /projectstakes anIdempotency-Keyheader: a repeat with the same key and body answers what the first call did, withIdempotency-Replayed: true, instead of creating a second project. New codesinvalid_idempotency_key,idempotency_in_progressandidempotency_key_reused. Repeating a create.GET /voices?language=&provider=lists known Amazon Polly, Azure and Google voices for a language. Choosing a voice.- A Deepdub
voiceother thanautois refused when the project is saved (422), instead of failing every file at processing time. - Webhooks:
POST /webhookssubscribes an HTTPS URL tofile.done,file.failed,project.stoppedandproject.error. Deliveries are signed as Standard Webhooks specifies, and retried for 24 hours. New codeswebhook_not_foundandwebhook_limit_reached. Webhooks. - A method a path does not have, such as
POST /projects/{id}, answers405method_not_allowedas Errors says, instead of404not_found. - In
GET /projects/{id}/filesthegrafanaUrlkey is gone, where it wasnull.
- Every error body has a stable
code, such asproject_not_foundorvalidation_failed: branch on it instead of the message. Errors. GET /projects?name=finds projects by their exact name, to look a project up before creating it again.- A
429carriesRetry-After, the seconds to wait, andX-RateLimit-Remaining: 0. GET /enums/languagesno longer listsHumanas a transcription engine: it is SyncWords’ live captioning, which VOD Express does not use.grafanaUrlis no longer shown to customers inGET /projects/{id}/files; it linked to an internal dashboard.GET /v1/openapi.jsonand Swagger UI describe only the calls a customer can make, and link each one to its guide.
- Transcription and translation configs are handled exactly as on SyncWords Live: engines left out are chosen for you and stored; an engine that does not support the language is refused when you save the project (for example, Soniox translation from English).
- Uploads through the API: S3 multipart uploads signed part by part, no AWS account needed. Upload through the API.
- An upload whose outputs another input already writes (
a.movbesidea.mkv) is refused with422. - A dub is a clean dub by default:
originalAudioSplittingistrueunless you set it. - Deepdub and Sarvam dubs get a pronunciation locale chosen from the language when you leave
ttsOptions.localeout; without one, Deepdub dubs were silent. - Embedded 608 captions without a
languageare refused when you save the project. - Failure texts (
failureReason,lastError) are general sentences; SyncWords support sees the details.
- Paths are under
/v1. options.autoStarton create; the service’s state is onGET /projects/{id}/status.- Inputs in subfolders of
input/are processed, and their outputs keep the subfolders.
- Idle projects stop themselves 30 minutes after their last file finished.
- Swagger UI at
/v1/docs.
Processing builds
2026-10-20 · default build
- The build the Config reference documents, and the oldest the API accepts. Every project was moved to it.
- Same config as
0.9.0-alpha1-2026-10-12T15-21Z-ed2c99for what you write; the S3 source and outputs can read and write a bucket of your own (Your own bucket). - A translation request that timed out once and was retried no longer fails the file.
…-3f05aa.
2026-10-12
- Same config as
0.9.0-alpha1-2026-10-09T16-39Z-dae007. - A dub track’s
titlereaches MP4 and MOV files, as the track’s handler name. - A feed and its items’ media are downloaded through redirects (up to 5, never from HTTPS to HTTP).
- Files are processed continuously: the next one starts as soon as one finishes.
- A file interrupted by a stop is cleaned up and processed again from the start on the next run.
2026-10-09
- A video or audio file’s audio is
useOriginalTracks, the input’s audio copied as it is and first, anddubTracks; its subtitles aresubTracks. Dub tracks carry no default flag. - An audio file holds exactly one audio track.
- Embedded CEA-608 captions can no longer be configured.
2026-10-09
- Same config as
0.9.0-alpha1-2026-10-07T11-55Z-b1b8d1. - A file whose voice or translation engine reported an error fails, instead of finishing with silent gaps or the original audio in its dub.
- A step stopped by the infrastructure (a machine taken away mid-file) is restarted instead of failing the file.
- Subtitles can replace the speaker label with any text, or remove it, through
options:speaker-label-replacement,collapse-speaker-labels. - A retried file is processed from the start, so it reflects a config or voice change made since.
2026-10-07
- RSS feeds beside Media RSS feeds:
RssSourceandRssOutputfor a feed of<enclosure>s,MrssSourceandMrssOutputfor<media:content>, the one inside a<media:group>included. Feeds. - A feed item’s file is named from its media URL alone (not the URL and duration), so a feed project moved onto this build processes every item again. A media URL whose bytes change is still not noticed.
- The published feed is written from a parsed model: standard elements first, the rest after;
media:content’sfileSize, andtype/mediumwhen the container changed, are updated.
2026-10-05
- Media RSS feeds:
MrssSourcereads a feed,MrssOutputpublishes it again per language. Media RSS feeds. - Fixes two causes of failed files: audio whose timestamps run backwards, and video streams carrying metadata the processing did not recognise.
- Every project on a build before
…-4787fbwas moved to this one.
2026-10-02
- The first build with
sourceMedia, andoutputsas destinations withitems; the input folder and the output folder only.
outputs.
2026-10-01
- Same
configas…-99cdd3, and the same results: the change is internal.
2026-09-29
- Reports each file’s duration, which usage is billed by.
- Same
configas…-118f0e.
2026-09-28
- Subtitle files and subtitle streams render without a 608 video output beside them.
- Same config schema as
…-fc1426.
2026-09-25
- Known issues: subtitles (fixed in
…-118f0e) and track titles.
2026-09-24
- The first build with
transcription,translationsand a list of files inoutputs. - Cannot process files; use a later build.