Update Robots requests, response handling, and caption track selection for v1 while keeping existing v0 jobs accessible.
Use this guide to move an existing integration from the Robots Beta API (/robots/v0) to the GA API (/robots/v1). V1 changes request fields, response shapes, caption track selection, and webhook event types. Changing the API URL alone is not enough.
Migrate with your coding agent
Paste this prompt into your agent to review your integration, apply the relevant changes, and test the migration.
The Robots v0 API is deprecated and remains available for six months after the v1 launch. Existing jobs and directives are tied to the API version used to create them. Creating v1 resources does not migrate existing v0 resources.
If you also use Directives or Robots webhooks, follow Migrate Robots Directives from Beta to GA and Migrate Robots webhooks from Beta to GA. See the Robots API referenceAPI for the full contracts.
During the migration, v0 and v1 run side by side. Jobs and Directives you already have stay on v0, while anything you create through v1 returns v1 response shapes and sends v1 webhook events. Follow these steps in order so your integration can handle both versions at every stage, and so you can switch new requests back to v0 until the cutover is complete.
V0 and v1 don't recognize each other's jobs as duplicates. Submitting the same job to both runs it twice, and both runs consume units. When comparing versions, use a test asset and review any options that write results back to the asset.
Change new job requests from /robots/v0/jobs/{workflow} to /robots/v1/jobs/{workflow}. Mux API authentication, access tokens, and the parameters request envelope stay the same.
For example, key-moment duration preferences change from integer milliseconds to seconds.
V0 request:
{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"target_duration_ms": { "min": 15000, "max": 45000 }
}
}V1 request:
{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"target_duration": { "min": 15, "max": 45 }
}
}Update these fields wherever you construct workflow requests, including Directive binding parameters.
| Workflow | V0 field | V1 action |
|---|---|---|
find-key-moments | target_duration_ms.min / .max | Use target_duration.min / .max, dividing values by 1,000. Fractional seconds with millisecond precision are supported. |
translate-audio, translate-captions | to_language_code | Rename to output_language_code. |
summarize, generate-chapters | prompt_overrides | Remove it and express supported preferences through output_steering. This is not a one-to-one prompt conversion. |
generate-premium-captions | replace_existing | Use replace_existing_tracks: true maps to "replace_all"; false maps to "fail". |
edit-captions | delete_original_track | Choose replace_existing_tracks: "replace" replaces the source, and "fail" keeps it and creates a separately named track. |
edit-captions | track_name_suffix | Supply the complete desired track_name instead. |
For edit-captions, preserving the source requires replace_existing_tracks: "fail" and a track_name different from the source track's name. The default v1 replacement policy is "replace". Review this explicitly if your v0 integration used the legacy naming or deletion options.
Unknown request fields are ignored, rather than treated as aliases. For example, sending only to_language_code to a v1 translation endpoint does not satisfy the required output_language_code field. Remove obsolete fields from your integration even when the request succeeds without them.
These changes apply to both a job's GET response and the data object of its v1 webhook.
Media offsets in v1 use seconds and can contain fractional values. These are positions on the original asset timeline, not Unix timestamps. A value of 23.456 represents the same position as 23456 milliseconds in v0.
| Workflow / output | V0 | V1 |
|---|---|---|
find-best-thumbnails, outputs.best_thumbnails[] | timestamp_ms | time |
find-key-moments, outputs.moments[] and nested cues[] | start_ms, end_ms | start_time, end_time |
find-key-moments, quotable_segment | start_ms | time |
generate-engagement-insights, outputs.moment_insights[] | start_ms, end_ms | start_time, end_time |
Remove any existing millisecond-to-second conversion when reading v1 values, or playback positions will be scaled twice. Unix timestamps such as created_at and updated_at already use seconds and do not need this conversion. Chapter start times already use seconds too.
| Workflow / output | V0 | V1 |
|---|---|---|
edit-captions, translate-captions, translate-audio | outputs.uploaded_track_id | outputs.track_id |
| Workflows reporting deleted tracks | replaced_tracks: [{ "id": "TRACK_ID", ... }] | replaced_track_ids: ["TRACK_ID"] |
generate-premium-captions, legacy alias | outputs.replaced_track_id | outputs.replaced_track_ids[] |
generate-premium-captions | outputs.detected_language | outputs.detected_language_code |
generate-chapters, legacy alias | outputs.asset_update | outputs.asset_updates.chapters |
generate-chapters, nested replacement outcome | asset_updates.chapters.replaced_track_id | asset_updates.chapters.replaced_track_ids[] |
replaced_track_ids contains IDs of tracks that were deleted. It is omitted when no deletions were recorded; do not assume it is always present. V1 no longer includes the metadata objects previously returned in replaced_tracks.
In caption editing and translation, parameters.track_id is the source track, while outputs.track_id identifies the newly created track.
Writing results back to the asset is best effort. A job can complete successfully while an asset update reports status: "failed", so check the corresponding asset_updates entry separately from the job status. Older jobs that recorded no update outcome omit it. For chapter replacement, a failed update with deleted track IDs means deletion succeeded but creation failed.
V1 uses the first ready caption track in asset track order, without preferring English. If your integration relied on the English preference, supply language_code explicitly when the workflow supports it.
An explicit source language_code must match exactly, including case and region. For example, en does not select an en-US caption track. When checking for an existing track in a translation's target language, or a track to replace, en and en-US count as the same language.
An explicit caption track_id must identify a ready caption track. Audio-only assets with exactly one ready text track that isn't marked as captions can use that track as a legacy transcript. Audio-only moderation no longer assumes language_code: "en" when you omit it.
Before switching production requests, test with assets that have multiple languages, text tracks that aren't captions, or captions that are still preparing. Jobs dispatched by a Directive follow the selection rules of the Directive's version.
find-scenes is not included in the v1 release. Use Analyze Structure (POST /robots/v1/jobs/analyze-structure) and read outputs.scenes. Analyze Structure also produces a shared title, summary, tags, chapters, and key moments.
curl https://api.mux.com/robots/v1/jobs/analyze-structure \
-u "$MUX_TOKEN_ID:$MUX_TOKEN_SECRET" \
-H "Content-Type: application/json" \
-d '{ "parameters": { "asset_id": "YOUR_ASSET_ID" } }'Update your scene parser for start_time and end_time in seconds, including nested cue and shot intervals. Review the Analyze Structure contract rather than copying Find Scenes parameters unchanged: its output steering and result structure are different, and generated scene boundaries can differ.
The v1 jobs list can discover jobs created through either version. Each summary includes _links.self.href, which points to the route for the version that created the job:
{
"id": "rjob_example",
"_links": {
"self": { "href": "/robots/v0/jobs/summarize/rjob_example" }
}
}This is an excerpt from a v1 list response. Follow the relative URL against https://api.mux.com rather than rebuilding it with /v1. List summaries do not contain full workflow parameters or outputs.
Detail and cancel requests must use the version that created the job. A v0 job requested through a v1 detail route returns 404; it is not converted into a v1 job on read. For cancellation, use POST /robots/{VERSION}/jobs/{JOB_ID}/cancel with that version.
Store the version that created each new job, and keep it in polling queues, saved job links, and retry/cancel actions. A v1 webhook identifies a v1-created job; a v0 webhook identifies a v0-created job.
Read error.messages[] instead of the removed error.message field. For example:
{
"error": {
"type": "track_not_ready",
"messages": ["No ready subtitle track available for this asset"]
}
}Handle errors according to their type and status rather than matching message strings.
| Situation | V1 response | Migration action |
|---|---|---|
| Malformed JSON | 400 | Correct the request encoding. |
| Invalid recognized parameters or malformed IDs | 422 validation_error | Correct the values or ID. |
| Invalid Mux credentials | 401 unauthorized | Check the credentials. |
| Preparing asset or required caption track | 409 asset_not_ready or 409 track_not_ready | Wait for the resource to become ready before retrying. |
| Duplicate active job | 409 conflict | Track the existing job instead of creating another. |
| Errored asset or unusable caption track | 422 | Correct the source; repeated readiness retries will not resolve it. |
| Missing resource or wrong API version | 404 | Check the ID, environment, and the API version that created the resource. |
These readiness and duplicate-job types describe job creation. Other operations can return 409 for operation-specific conflicts, such as cancelling a job already in a terminal state.
/robots/v1 and the renamed parameters.error.messages[]._links.self, and stored jobs keep the API version that created them.