Two things change independently:
  • 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 buildVersion until you change it, so a new build never changes an existing project. GET /build-versions lists them; your default is in GET /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 or PATCH. 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/settings sets a default connection for projects created without storage. Your own bucket.
  • storage.connection on the project resource: null for SyncWords’ storage, else the connection’s id, name, bucket and endpoint. Existing projects read null.
  • 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 build 0.9.0-alpha1-2026-10-20T14-10Z-3f05aa or 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-3f05aa are no longer listed by GET /build-versions or accepted in buildVersion.
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-PUT upload. Until now only an API upload in parts did this, and a file copied in waited as pending for POST /projects/{id}/start. A project stopped with POST …/stop, created with autoStart: false and never started, stopped after its service failed, or in error still waits. Calling start after an upload stays harmless.
  • startOnNewFiles, a new project field (default true), set on create and changed with PATCH: false keeps a stopped project stopped whatever arrives, including a completed API upload, until POST …/start. Retrying a file still starts it. Existing projects read true, 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 are pending, processing, done and failed, with total and countedAt, the same counts as meta of GET …/files. Kept on the project, so GET /projects shows 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. null until the first count. Projects.
  • GET /projects?status=completed lists the stopped projects whose files are all finished (done or failed) with at least one done, and ?status=failed those in error plus the stopped ones whose files all failed, as last counted.
Upload a file in one PUT
  • POST /projects/{id}/uploads also answers url: a presigned S3 PUT for the whole file, for a file of 5 GB or under that is not replacing one already in input/. PUT the file to it and it is in input/: no parts, no complete call. urlExpiresAt says 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-feed follow 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-ed2c99 are no longer listed by GET /build-versions or accepted in buildVersion.
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.
  • audioTracks is gone from VideoFile and AudioFile. useOriginalTracks: true copies the input file’s own audio as it is, with its own language tag, title and default flag, and always comes first; dubTracks lists the dubs after it, each {language, codec, title}. language: "original" and a track’s default are 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 useOriginalTracks out.
  • subtitleTracks is now subTracks, and its entries have no @type: language, options, subtitleCodec. Their errors are under …/subTracks/{n}/….
  • Embedded CEA-608 captions are gone: StreamingEmbedded608 can no longer be configured. Use subtitle tracks or subtitle files.
  • An AudioFile holds exactly one audio track: useOriginalTracks: true or one dubTracks entry. A file with neither, with both or with two dubs is refused with 422, and so is the input’s audio in an mp3 or wav file: it is copied as it is, so use ipod (.m4a) or matroska. AudioFile.
  • Existing projects: dubs became dubTracks in their order, without default; an original track became useOriginalTracks: 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_translation and unused_dub messages speak of dub tracks.
  • Builds before 0.9.0-alpha1-2026-10-09T16-39Z-dae007 are no longer listed by GET /build-versions or accepted in buildVersion.
Build 3cf17c; files without error counts
With processing build 0.9.0-alpha1-2026-10-09T14-08Z-3cf17c, the new default:
  • errors and warnings are gone from GET /projects/{id}/files and from the file.done webhook. 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) is failed instead of done with gaps: see failureCode, and retry it.
  • GET /projects/{id}/files/{name}/meta documents 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’s options say otherwise. Speaker changes.
Tokens from this API
  • Your account’s dictionaries and glossaries. transcription.dictionary and postprocessingDictionary take a dictionary of your SyncWords Live account by id or name, and a translation engine’s glossary a glossary’s id, beside the inline forms. A field left out takes your account’s default for the language; null takes none. A project that leaves them out starts with your defaults applied the next time it starts. See Your account’s dictionaries.
  • POST /token/create exchanges 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), plus expires_in where tokens expire by age, and a wrong pair is 401 invalid_credentials. Tokens from the Live API’s POST /v2/token/create keep 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), beside MrssSource, 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: RssOutput for an RssSource, MrssOutput for an MrssSource; 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/check takes sourceType (RssSource or MrssSource, the latter when left out), and every feed check answers sourceType and 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.messages on every project: what its config will do that you probably do not mean, each with a severity, a stable code, the JSON path it is about, a message and its params. Nothing is refused for it. The first two codes: unused_translation, a translation no output carries, and unused_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 sourceMedia URL is fetched and read the way the project reads it. A feed that does not answer 2xx (redirects included), is not RSS 2.0, or has items none of which links a media file is refused under errors["/config/sourceMedia/url"], with the reason. A feed with no items yet is accepted. Media RSS feeds.
  • GET /projects/{id}/source-feed reads 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_folder for a folder project.
  • POST /source-feeds/check with {"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.
  • outputs lists destinations, each with its items. The files you listed in outputs go into the items of 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.
  • sourceMedia says 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 input field is gone: the project resource no longer has it, and a body that sends it is refused with 422 under errors.input, pointing to config.sourceMedia. The code input_type_not_available is 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. An MrssOutput per language publishes the feed again with the dubbed files, public at GET /feeds/{projectId}/{language}/feed.xml, its media at GET /feeds/{projectId}/{language}/media/{name}. A feed project takes no uploads (409, new code project_reads_feed) and is never stopped for being idle; a feed not written yet answers 404 with the new code feed_not_found. Media RSS feeds.
  • The API fills in every location: a path on S3FolderSource or S3FolderOutput, or path, mediaPath or mediaUrl on MrssOutput, is refused.
  • GET /enums/source-types and GET /enums/destination-types list the new @types; GET /enums/output-types lists the item kinds, as before.
  • Builds before 0.9.0-alpha1-2026-10-02T14-37Z-4787fb are no longer listed by GET /build-versions or accepted in buildVersion.
Files
  • usage on every input file: what a done file 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.configLocked on every project: true while SyncWords support manages the project’s configuration for you. Meanwhile a change of config or buildVersion is refused with 409 and the new code project_config_locked; name and description still change, and a config equal to the stored one is accepted. Projects.
Voices
  • "@type": "ElevenLabs" is no longer a voice provider: a project that names it is refused with 422. 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.
  • MultiVoice takes no voices: it gives each speaker a voice from SyncWords’ voices for the translation’s language, and a language without them is refused with 422 when the project is saved. A voices list 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 beside config on every project resource: where its media comes from. {"type": "folder"}, the input folder, is what every project is and the default when POST /projects leaves it out; it is set on create, and PUT/PATCH refuse it.
  • The mrss input 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 /projects validates the body and then answers 422 with the new code input_type_not_available, creating nothing. Inputs.
Webhooks
  • PATCH /webhooks/{id} changes a webhook’s url or events without a new secret; POST /webhooks/{id}/rotate-secret replaces the secret, the old one signing beside it for 24 hours; POST /webhooks/{id}/deliveries/{eventId}/retry sends a delivery again. New code webhook_delivery_not_found. Webhooks.
  • GET /webhooks/{id}/deliveries is paged (page, perPage, links, meta) and takes ?status=pending|delivered|failed. data is 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’s hash is 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 failed for 2 hours is stopped (project.stopped, reason: "idle"); pod.at is 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 /projects takes an Idempotency-Key header: a repeat with the same key and body answers what the first call did, with Idempotency-Replayed: true, instead of creating a second project. New codes invalid_idempotency_key, idempotency_in_progress and idempotency_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 voice other than auto is refused when the project is saved (422), instead of failing every file at processing time.
  • Webhooks: POST /webhooks subscribes an HTTPS URL to file.done, file.failed, project.stopped and project.error. Deliveries are signed as Standard Webhooks specifies, and retried for 24 hours. New codes webhook_not_found and webhook_limit_reached. Webhooks.
  • A method a path does not have, such as POST /projects/{id}, answers 405 method_not_allowed as Errors says, instead of 404 not_found.
  • In GET /projects/{id}/files the grafanaUrl key is gone, where it was null.
  • Every error body has a stable code, such as project_not_found or validation_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 429 carries Retry-After, the seconds to wait, and X-RateLimit-Remaining: 0.
  • GET /enums/languages no longer lists Human as a transcription engine: it is SyncWords’ live captioning, which VOD Express does not use.
  • grafanaUrl is no longer shown to customers in GET /projects/{id}/files; it linked to an internal dashboard.
  • GET /v1/openapi.json and 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.mov beside a.mkv) is refused with 422.
  • A dub is a clean dub by default: originalAudioSplitting is true unless you set it.
  • Deepdub and Sarvam dubs get a pronunciation locale chosen from the language when you leave ttsOptions.locale out; without one, Deepdub dubs were silent.
  • Embedded 608 captions without a language are refused when you save the project.
  • Failure texts (failureReason, lastError) are general sentences; SyncWords support sees the details.
  • Paths are under /v1.
  • options.autoStart on create; the service’s state is on GET /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-ed2c99 for 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.
The builds below are no longer listed or accepted, and their projects now run on …-3f05aa.
2026-10-12
  • Same config as 0.9.0-alpha1-2026-10-09T16-39Z-dae007.
  • A dub track’s title reaches 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, and dubTracks; its subtitles are subTracks. 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: RssSource and RssOutput for a feed of <enclosure>s, MrssSource and MrssOutput for <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’s fileSize, and type/medium when the container changed, are updated.
2026-10-05
  • Media RSS feeds: MrssSource reads a feed, MrssOutput publishes 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 …-4787fb was moved to this one.
2026-10-02
  • The first build with sourceMedia, and outputs as destinations with items; the input folder and the output folder only.
The builds below took the earlier config, with a list of files in outputs.
2026-10-01
  • Same config as …-99cdd3, and the same results: the change is internal.
2026-09-29
  • Reports each file’s duration, which usage is billed by.
  • Same config as …-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, translations and a list of files in outputs.
  • Cannot process files; use a later build.