# Translate captions
Translate existing captions to another language using the Mux Robots API.
Translate an existing caption track on a Mux asset from one language to another. The translated captions can be automatically attached to the asset as a new text track, making multilingual video accessible with a single API call. See the <ApiRefLink href="/docs/api-reference/robots/translate-captions">Translate 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 translation requires an existing caption track on the asset. Make sure your asset has captions, either [auto-generated](/docs/guides/add-autogenerated-captions-and-use-transcripts) or [manually added](/docs/guides/add-subtitles-to-your-videos), before creating a translate-captions job.
</Callout>

## Create a `translate-captions` job

```bash
curl https://api.mux.com/robots/v0/jobs/translate-captions \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{
    "parameters": {
      "asset_id": "YOUR_ASSET_ID",
      "track_id": "YOUR_TRACK_ID",
      "to_language_code": "es"
    }
  }' \
  -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.translate_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/translate-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 captions will be translated. |
| `track_id` | string | **Required.** The text track ID of the source caption track to translate. |
| `to_language_code` | string | **Required.** BCP 47 target language code (e.g. `es`, `ja`). |
| `upload_to_mux` | boolean | Whether to upload the translated VTT and attach it as a text track on the asset. Defaults to `true`. |

## Output

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

| Field | Type | Description |
| :-- | :-- | :-- |
| `track_id` | string | The text track ID of the source caption track that was translated. |
| `uploaded_track_id` | string | Mux text track ID of the uploaded translated captions. Present when `upload_to_mux` is `true`. |
| `temporary_vtt_url` | string | Temporary pre-signed URL to download the translated VTT file. Present when `upload_to_mux` is `true`. |

## Example response

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

```json
{
  "data": {
    "id": "rjob_pqr678",
    "workflow": "translate-captions",
    "status": "completed",
    "units_consumed": 1,
    "parameters": {
      "asset_id": "YOUR_ASSET_ID",
      "track_id": "YOUR_TRACK_ID",
      "to_language_code": "es",
      "upload_to_mux": true
    },
    "outputs": {
      "track_id": "YOUR_TRACK_ID",
      "uploaded_track_id": "track_abc123",
      "temporary_vtt_url": "https://storage.googleapis.com/..."
    }
  }
}
```

<Callout type="info">
  When `upload_to_mux` is `true` (the default), the translated caption track is automatically attached to your asset. Your viewers will see the new language option in the player's caption menu without any additional work.
</Callout>
