# Edit a video's captions
Edit an existing caption track on a Mux asset using static find/replace rules and optional LLM-driven profanity censoring with the Mux Robots API.
<Callout type="warning" title="Experimental">
  The `edit-captions` workflow is experimental. The API shape, parameters, behavior, and pricing may change. If we make changes to this workflow while you're using it, we'll let you know via email.

  `edit-captions` can be enabled by [contacting our support team](/support).
</Callout>

Edit an existing text track on a Mux asset. The workflow supports two kinds of edits — static word/phrase `replacements` and LLM-driven profanity censoring via `auto_censor_profanity` — and you can combine them in a single job. By default the edited captions are uploaded back to the asset as a new text track and the original track is deleted. See the <ApiRefLink href="/docs/api-reference/robots/edit-captions">Edit Captions API reference</ApiRefLink> for the full endpoint specification. See [Mux Robots pricing](/docs/pricing/overview#mux-robots-pricing) for unit costs.

<Callout type="info">
  Caption editing requires an existing, ready text track on the asset. Add captions first, either [auto-generated](/docs/guides/add-autogenerated-captions-and-use-transcripts) or [manually added](/docs/guides/add-subtitles-to-your-videos), before creating an edit-captions job. You must provide at least one of `replacements` or `auto_censor_profanity`.
</Callout>

## Create an `edit-captions` job

```bash
curl https://api.mux.com/robots/v0/jobs/edit-captions \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{
    "parameters": {
      "asset_id": "YOUR_ASSET_ID",
      "track_id": "YOUR_TRACK_ID",
      "replacements": [
        { "find": "Mucks", "replace": "Mux", "case_sensitive": true },
        { "find": "gonna", "replace": "going to" }
      ],
      "auto_censor_profanity": {
        "mode": "blank"
      }
    }
  }' \
  -u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET}
```

<Callout type="info">
  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.job.edit_captions.completed` webhook](/docs/guides/robots#webhooks)** — the payload contains the full completed job, so no follow-up API call is needed. If webhooks aren't an option, you can poll `GET /robots/v0/jobs/edit-captions/{JOB_ID}` with the `id` from the response until the status is `completed`.
</Callout>

## Parameters

| Parameter | Type | Description |
| :-- | :-- | :-- |
| `asset_id` | string | **Required.** The Mux asset ID whose text track will be edited. |
| `track_id` | string | **Required.** The existing, ready Mux text track ID to edit. |
| `replacements` | array | Static find/replace rules applied to cue text. See [Replacements](#replacements) below. |
| `auto_censor_profanity` | object | LLM-driven profanity detection and censorship rules. See [Auto-censor profanity](#auto-censor-profanity) below. |
| `upload_to_mux` | boolean | Whether to upload the edited VTT back to the asset as a new text track. Defaults to `true`. |
| `delete_original_track` | boolean | Whether to delete the source text track after the edited track upload succeeds. Only applies when `upload_to_mux` is `true`. Defaults to `true`. |
| `track_name_suffix` | string | Suffix appended to the uploaded replacement track's name. Defaults to `edited`. |

### Replacements

Each entry in `replacements` is applied to every cue in the source track.

| Field | Type | Description |
| :-- | :-- | :-- |
| `find` | string | **Required.** Exact word or phrase to match in cue text. |
| `replace` | string | **Required.** Text to insert when a match is found. Use an empty string to delete the match. |
| `case_sensitive` | boolean | When `true`, `find` only matches with exact case. Defaults to `false`, so `gonna` also matches `Gonna` and `GONNA`. |

### Auto-censor profanity

Use `auto_censor_profanity` to detect and replace profane terms automatically.

| Field | Type | Description |
| :-- | :-- | :-- |
| `mode` | string | Replacement strategy: `blank` (bracketed underscores, e.g. `[____]`), `remove` (drop the match entirely), or `mask` (replace characters with question marks). Defaults to `blank`. |
| `always_censor` | array of strings | Words or short phrases that should always be censored, even if the model doesn't flag them. |
| `never_censor` | array of strings | Words or short phrases that should never be censored, even if the model flags them. |

## Output

The `outputs` object is included once the job's status is `completed`. You'll receive it on the [`robots.job.edit_captions.completed`](/docs/guides/robots#webhooks) webhook (recommended), or you can fetch it with `GET /robots/v0/jobs/edit-captions/{JOB_ID}`. It contains:

| Field | Type | Description |
| :-- | :-- | :-- |
| `total_replacement_count` | integer | Total number of cue text replacements applied across all edit operations. |
| `uploaded_track_id` | string | Mux text track ID for the uploaded edited captions. Present when `upload_to_mux` is `true` and the upload succeeds. |
| `temporary_vtt_url` | string | Temporary pre-signed URL to download the edited VTT file. The URL expires 7 days after the job completes. |

## Example response

This is the payload delivered to the [`robots.job.edit_captions.completed`](/docs/guides/robots#webhooks) webhook, and the same shape you get from `GET /robots/v0/jobs/edit-captions/{JOB_ID}`:

```json
{
  "data": {
    "id": "rjob_example123",
    "workflow": "edit-captions",
    "status": "completed",
    "units_consumed": 1,
    "parameters": {
      "asset_id": "mux_asset_123abc",
      "track_id": "text_track_456def",
      "replacements": [
        { "find": "Mucks", "replace": "Mux", "case_sensitive": true },
        { "find": "gonna", "replace": "going to" }
      ],
      "upload_to_mux": true,
      "delete_original_track": true
    },
    "outputs": {
      "total_replacement_count": 5,
      "uploaded_track_id": "text_track_789ghi",
      "temporary_vtt_url": "https://s3.example.com/edited.vtt?sig=abc"
    }
  }
}
```

<Callout type="info">
  When `upload_to_mux` is `true` (the default), the edited caption track is automatically attached to your asset and — unless you set `delete_original_track` to `false` — the original source track is removed. To keep the original track alongside the edited version, set `delete_original_track` to `false`.
</Callout>
