Turn an asset into social posts, blog posts, or newsletter copy with the Mux Robots API, and steer the voice, audience, and call to action. Request named variants of a shared set of written artifacts.
You can use the Generate Contextual Text workflow to turn an interview, tutorial, product demonstration, or any other video, into social posts, blog posts, and newsletter copy grounded in the source media. You can request all the outputs together, and use variants to get more than one version of the whole set: independent takes to choose between, or different angles you describe with instructions. See the Generate Contextual Text API referenceAPI for the full endpoint specification. See Mux Robots pricing for unit costs.
The workflow builds a shared editorial brief from the asset's central idea, supporting points, and concrete details, then writes each artifact from that brief. The text addresses the subject directly: a tutorial can become an instructional article, and a product demonstration can become promotional copy.
For a simple title, description, and tags workflow, use Summarize.
The asset must be ready, no longer live, and have a public or signed playback ID and a ready caption track. Audio-only assets can also use a single ready legacy text track that isn't marked as captions. Generate captions or add your own captions before creating a job. Video assets include a storyboard as visual context; the transcript remains the authoritative source.
generate-contextual-text jobAn artifact is one deliverable. A variant is a named version of every requested artifact. Two variants and two artifacts produce four pieces of text. A variant's key only labels it in the results. Any difference in angle comes from its instructions.
curl https://api.mux.com/robots/v1/jobs/generate-contextual-text \
-H "Content-Type: application/json" \
-X POST \
-d '{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"output_language_code": "en",
"output_steering": {
"audience": "video developers",
"voice": "conversational"
},
"variants": [
{ "key": "option_a", "instructions": "Playful voice for developers who are new to video." },
{ "key": "option_b" }
],
"artifacts": [
{ "key": "x_post", "channel": "x", "max_length": { "unit": "characters", "value": 280 } },
{ "key": "blog_post", "instructions": "Write a short blog post.", "max_length": { "unit": "words", "value": 1200 }, "format": "markdown" }
]
}
}' \
-u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET}This request is asynchronous. The POST returns immediately with the job in pending status and does not include results. We strongly recommend listening for the robots.v1.job.generate_contextual_text.completed webhook. The payload contains the full completed job, so no follow-up API call is needed. If webhooks aren't an option, poll GET /robots/v1/jobs/generate-contextual-text/{JOB_ID} with the id from the response until the status is completed. Jobs are automatically deleted after 30 days.
| Parameter | Type | Description |
|---|---|---|
asset_id | string | Required. The Mux video or audio asset ID whose transcript grounds the text. |
variants | array | Required. 1–5 named versions of the complete artifact set. See Variants and artifacts. |
artifacts | array | Required. 1–5 deliverables to generate for each variant. See Variants and artifacts. |
language_code | string | BCP 47 language code of the caption source. An explicit value must match a ready source exactly, including case: en does not match en-US. When omitted, the first ready caption track is selected. Audio-only assets can also use a single ready legacy text track. |
output_language_code | string | BCP 47 language code for generated text. Defaults to the selected transcript track's language when available. |
use_shots | boolean | When true, generates or reuses Mux Shots and adds a bounded sample of shot frames as visual evidence. Omitted or false uses the storyboard without additional shot frames. Rejected for audio-only assets. Shot generation can incur separate Mux Video charges. |
output_steering | object | Shared controls for the analyzed time range, audience, voice, call to action, and brand terminology. See Output steering. |
See language support for Mux Robots for verified languages and language tags.
Each variant and artifact needs a key: a lowercase snake_case identifier starting with a letter, up to 64 characters. Keys must be unique within each array. A key identifies the result; it does not guide generation. Use instructions to describe the angle or deliverable.
Naming a variant funny does not make it funny. Omit instructions to get independent takes on the same brief, which is useful when you want several options to choose from or test. Add instructions when each variant should take a specific angle.
Output steering applies to every variant. To give variants different voices or audiences, describe them in each variant's instructions, for example "Playful voice for developers who are new to video".
Each generated artifact in each variant costs 250 units, in addition to the job's base and duration charges. Two variants with two artifacts count as four artifacts. See Mux Robots pricing.
| Field | Type | Description |
|---|---|---|
variants[].key | string | Required. Identifier returned with this variant. |
variants[].instructions | string | Optional guidance for the variant's angle, 1–500 characters. Omit it to request an independent take on the shared brief. |
artifacts[].key | string | Required. Identifier returned with this artifact in every variant. |
artifacts[].instructions | string | Optional guidance for the deliverable, 1–500 characters. |
artifacts[].channel | string | Publishing conventions and default length. Supported values: generic, x, linkedin, facebook, instagram, tiktok, and youtube. Defaults to generic. |
artifacts[].max_length | object | Hard output cap with unit (characters or words) and integer value. Character caps range from 10 to 20,000; word caps range from 5 to 3,000. Defaults to the channel's cap. x always also enforces 280 characters, even when you specify a word cap. |
artifacts[].format | string | plain (default) or markdown. Use markdown when the result should be allowed to include Markdown formatting. |
Default channel caps are 300 words for generic and linkedin, 250 words for facebook and youtube, 100 words for tiktok, 1,500 characters for instagram, and 280 characters for x. An explicit max_length overrides the default, subject to the x ceiling.
Each artifact aims for about 90% of its cap, whatever the length of the source. A one-minute video and a 15-minute video get text of about the same length, so set max_length to the length you want rather than relying on the channel default.
generic has no platform conventions; its style follows the length cap. Short caps produce a single focused piece. For a blog post, article, or newsletter entry, use generic with a max_length above 600 words and format: "markdown", as in the blog_post artifact above.
Scope limits which transcript cues and visual context ground the text. The other controls apply best-effort writing guidance to every artifact and do not guarantee exact wording.
| Field | Type | Description |
|---|---|---|
scope | object | Execution window in seconds on the original asset timeline. Supply start_time, end_time, or both. An omitted start means the beginning; an omitted end means the asset's end. The start must be nonnegative, the end must be positive, and the start must precede the end. An end past the asset's duration is clamped to the asset's end, and a range that starts at or after the asset's end is rejected. |
audience | string | Intended reader, up to 160 characters. |
voice | string | conversational, editorial, playful, or professional. |
call_to_action | string | none, soft, or direct, guiding whether and how text invites further engagement. |
brand_terms | array of strings | Preferred terms to use when the source supports them. Supply 1–10 terms, up to 40 characters each and 240 characters combined. |
For example, generate copy from just the first two minutes:
{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"variants": [{ "key": "main" }],
"artifacts": [{ "key": "post", "channel": "linkedin" }],
"output_steering": {
"scope": { "start_time": 0, "end_time": 120 },
"audience": "video developers",
"voice": "professional",
"call_to_action": "soft",
"brand_terms": ["Mux Video"]
}
}
}The selected range must contain usable transcript evidence. A range with no usable transcript cues cannot produce grounded text and the job can fail during processing.
The outputs object is included once the job is completed, in the robots.v1.job.generate_contextual_text.completed webhook or the job's GET response.
| Field | Type | Description |
|---|---|---|
variants | array | Generated versions of the complete artifact set. |
variants[].key | string | The requested variant key. |
variants[].artifacts | array | Generated deliverables for this variant. |
variants[].artifacts[].key | string | The requested artifact key. |
variants[].artifacts[].content | string | Generated text in the requested format, constrained by the artifact's length cap. |
Match results to your request using the variant and artifact keys. Each returned artifact in each variant counts once toward unit consumption.
This example uses a two-minute asset with two variants and two artifacts, consuming 1,520 units. It is the job delivered in the robots.v1.job.generate_contextual_text.completed webhook's data field and returned by GET /robots/v1/jobs/generate-contextual-text/{JOB_ID}:
{
"data": {
"id": "rjob_abc123",
"workflow": "generate-contextual-text",
"status": "completed",
"units_consumed": 1520,
"created_at": 1746403200,
"updated_at": 1746403260,
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"output_language_code": "en",
"output_steering": { "audience": "video developers", "voice": "conversational" },
"variants": [
{ "key": "option_a", "instructions": "Playful voice for developers who are new to video." },
{ "key": "option_b" }
],
"artifacts": [
{ "key": "x_post", "channel": "x", "max_length": { "unit": "characters", "value": 280 }, "format": "plain" },
{ "key": "blog_post", "instructions": "Write a short blog post.", "channel": "generic", "max_length": { "unit": "words", "value": 1200 }, "format": "markdown" }
]
},
"outputs": {
"variants": [
{
"key": "option_a",
"artifacts": [
{ "key": "x_post", "content": "Never shipped video before? Make a direct upload, send your file, and grab the playback ID. That's the whole trip from your laptop to a working player with Mux Video." },
{ "key": "blog_post", "content": "# Your first video, start to finish\n\nGood news: getting a video from your laptop into a player takes three steps. First, create a direct upload. Once the video is ready, its playback ID connects the uploaded asset to your player." }
]
},
{
"key": "option_b",
"artifacts": [
{ "key": "x_post", "content": "Uploading a video and playing it are separate steps. Follow the asset until it is ready, then use its playback ID to load the player." },
{ "key": "blog_post", "content": "# Understand the upload lifecycle\n\nA direct upload creates a destination for your video. The walkthrough then follows the uploaded asset to readiness before loading it into a player." }
]
}
]
}
}
}