> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.voicecheap.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Doppiaggio del progetto

> Doppia un progetto già trascritto a partire dal tuo SRT tradotto

# Doppiaggio del progetto

Genera le voci e mixa l'output di un progetto esistente a partire da un SRT tradotto che fornisci tu. VoiceCheap non traduce nulla su questo endpoint: niente motore di traduzione, niente riformulazione SmartSync, niente glossario. Ogni cue viene letto così com'è sul segmento corrispondente della trascrizione del progetto, poi mixato con lo sfondo originale, i sottotitoli e la sincronizzazione labiale facoltativa, esattamente come una traduzione normale.

Usalo quando la traduzione è prodotta altrove (un traduttore umano, i tuoi strumenti, un flusso di automazione) e ti serve VoiceCheap solo per generare le voci. L'esecuzione è asincrona: interroga [Ottieni lo stato della traduzione](/docs/it/api-reference/translation-status) oppure ascolta i [Webhook](/docs/it/api-reference/webhooks).

## Prerequisiti

* Il progetto deve esistere e la sua trascrizione deve essere completa: crealo con [Crea progetto](/docs/it/api-reference/create-project) (solo trascrizione) o [Avvia traduzione](/docs/it/api-reference/translate), e attendi `transcriptionStatus: "success"`.
* Il tuo SRT deve coprire la trascrizione del progetto: ogni segmento ha bisogno di almeno un cue e ogni cue deve cadere su un segmento. Esporta la trascrizione con [Esporta trascrizione del progetto](/docs/it/api-reference/project-transcript) e traducila cue per cue per mantenere i timecode.
* La richiesta viene addebitata come una traduzione dello stesso media, con lo stesso controllo dei crediti. Le modalità di sincronizzazione labiale aggiungono i soliti crediti extra.

## Limite di concorrenza

La creazione dei progetti, la traduzione e il doppiaggio verificano tutti il limite di traduzioni attive dell’account (al massimo 10, eventualmente meno). Solo le traduzioni o i doppiaggi in corso occupano posti; i progetti di sola trascrizione no. Al raggiungimento del limite, l’API restituisce `CONCURRENT_TRANSLATION_LIMIT_REACHED` (HTTP 429). Il limite applicato è indicato in `details.limit`.

Una seconda esecuzione per lo stesso progetto e la stessa lingua di destinazione viene rifiutata finché un’altra è in corso (`TRANSLATION_ALREADY_IN_PROGRESS`, HTTP 409).

## Richiesta

Questo endpoint accetta un corpo JSON (`Content-Type: application/json`). Le opzioni booleane e numeriche vanno inviate come valori JSON, non come stringhe.

### Intestazioni

<ParamField header="x-api-key" type="string" required>
  La tua chiave API VoiceCheap. Ottienine una da [app.voicecheap.ai/page-api](https://app.voicecheap.ai/page-api).
</ParamField>

### Parametri del percorso

<ParamField path="projectId" type="string" required>
  L'identificatore del progetto restituito da [Crea progetto](/docs/it/api-reference/create-project) o [Avvia traduzione](/docs/it/api-reference/translate).
</ParamField>

### Parametri del corpo

<ParamField body="targetLanguage" type="string" required>
  La lingua di `translatedSrt`, in minuscolo, dallo stesso elenco di [Avvia traduzione](/docs/it/api-reference/translate). Se il progetto non ha ancora un lavoro per questa lingua, ne viene creato uno e la lingua viene aggiunta al progetto.
</ParamField>

<ParamField body="translatedSrt" type="string" required>
  Il contenuto SRT finale nella lingua di destinazione (numero del cue, riga dei tempi, testo). Massimo 1.000.000 di caratteri. I cue vengono abbinati ai segmenti della trascrizione tramite i timestamp: un cue che inizia entro 50 ms dall'inizio di un segmento viene assegnato a quel segmento, altrimenti al segmento con cui si sovrappone di più. Più cue sullo stesso segmento vengono uniti con uno spazio. Tempo, parlante e ordine di ogni segmento letto provengono sempre dalla trascrizione del progetto; i tuoi timecode servono solo per l'abbinamento.
</ParamField>

<ParamField body="webhookUrl" type="string">
  Un endpoint https che da questo momento riceve gli [eventi webhook](/docs/it/api-reference/webhooks) di questo progetto e sostituisce l'endpoint configurato sull'account.

  **Predefinito:** L'endpoint già salvato nel progetto, poi l'endpoint webhook dell'account.
</ParamField>

<ParamField body="keepBackgroundMusic" type="boolean">
  Mantenere l'audio di sottofondo originale (musica, ambiente) sotto le voci generate.

  **Predefinito:** `true`
</ParamField>

<ParamField body="keepOriginalVoice" type="boolean">
  Mantenere la voce originale a basso volume sotto la voce generata.

  **Predefinito:** `false`
</ParamField>

<ParamField body="originalVoiceVolume" type="number">
  Volume della voce originale da `1` a `70` quando `keepOriginalVoice` è attivo.

  **Predefinito:** `30`
</ParamField>

<ParamField body="voiceMode" type="string">
  Strategia vocale: `cloning` (clonare le voci dei parlanti del progetto) o `custom` (usare una voce del catalogo o la tua voce personalizzata salvata).

  **Predefinito:** `cloning`
</ParamField>

<ParamField body="voiceId" type="string">
  Obbligatorio quando `voiceMode` è `custom`. Usa un ID di `dubbing_voices_list`: una voce del catalogo o una voce personalizzata salvata dall’account
  autenticato. La fatturazione del team non concede accesso alle voci salvate degli altri membri.
</ParamField>

<ParamField body="voiceIsolatorOption" type="string">
  Modalità di isolamento della voce quando `keepBackgroundMusic` è attivo: `studio` o `realistic`.

  **Predefinito:** `studio`
</ParamField>

<ParamField body="subtitles" type="boolean">
  Masterizzare i sottotitoli nel video di output. Richiede un progetto video.

  **Predefinito:** `false`
</ParamField>

<ParamField body="subtitlesSource" type="string">
  Testo dei sottotitoli quando `subtitles` è attivo: `translated` (il tuo SRT) o `original` (la trascrizione di origine).

  **Predefinito:** `translated`
</ParamField>

<ParamField body="lipSyncMode" type="string">
  Esegui la sincronizzazione labiale quando il doppiaggio è pronto: `standard`, `pro` o `studio`. Le regole di piano, durata e crediti sono le stesse di [Avvia traduzione](/docs/it/api-reference/translate). Richiede un progetto video.

  **Predefinito:** ometti il campo per saltare la sincronizzazione labiale.
</ParamField>

<ParamField body="activeSpeakerDetectionEnabled" type="boolean">
  Abilita il rilevamento del parlante attivo per l'esecuzione di sincronizzazione labiale richiesta.

  **Predefinito:** `false`
</ParamField>

<ParamField body="voiceCloningSettings" type="object">
  Regolazione fine del clonaggio vocale, come oggetto JSON con `stability` e `similarity` tra `0` e `1`. Solo con `voiceMode: "cloning"`. Vedi [Avvia traduzione](/docs/it/api-reference/translate) per il significato di ciascun valore.
</ParamField>

<ParamField body="translationTimeSkips" type="array">
  Intervalli del tempo sorgente da lasciare nella lingua originale, come `[{ "startTime": 10.2, "endTime": 12.8 }]`. Richiede un progetto video e `keepBackgroundMusic: true`, non può essere combinato con `keepOriginalVoice` e non può sovrapporsi ai segmenti della trascrizione.
</ParamField>

## Risposta

<ResponseField name="success" type="boolean" required>
  Sempre `true` per le richieste riuscite.
</ResponseField>

<ResponseField name="message" type="string" required>
  Una conferma leggibile.
</ResponseField>

<ResponseField name="projectId" type="string" required>
  Il progetto che viene doppiato.
</ResponseField>

<ResponseField name="workId" type="string" required>
  Il lavoro di traduzione usato per `targetLanguage`. Corrisponde a `workId` negli endpoint di stato, dettagli e trascrizione.
</ResponseField>

<ResponseField name="estimatedDuration" type="number" required>
  Stima approssimativa dell'elaborazione in minuti: cinque minuti di elaborazione per ogni minuto iniziato del media sorgente.
</ResponseField>

```json Response theme={null}
{
  "success": true,
  "message": "Dubbing started successfully from the provided translation. Use the status endpoint to track progress.",
  "projectId": "project_123",
  "workId": "work_456",
  "estimatedDuration": 10
}
```

## Seguire l'esecuzione

Il progetto passa al flusso `translation` non appena parte il doppiaggio, quindi [Ottieni lo stato della traduzione](/docs/it/api-reference/translation-status) segue la nuova esecuzione: `status` passa da `processing` a `success` (con `translatedVideoUrl` e `translatedAudioUrl`) oppure a `failed` (con `error`). I webhook `project.translation.completed` e `project.translation.failed` vengono inviati con lo stesso `targetLanguage`. In [Ottieni dettagli del progetto](/docs/it/api-reference/project-details), la versione tradotta riporta `settings.dubbingMode: "dub-only"` e `settings.smartSync: false`.

Gli errori di allineamento compaiono dopo l’accettazione della richiesta POST. L’endpoint di stato restituisce `status: "failed"` con `error.code` e `error.message`; il webhook `project.translation.failed` contiene lo stesso codice e messaggio. `TRANSLATED_SRT_UNMATCHED_CUES` indica nel messaggio i numeri dei cue senza corrispondenza e `TRANSLATED_SRT_MISSING_SEGMENTS` gli indici dei segmenti senza cue. Queste risposte asincrone non includono un campo `details` strutturato. Correggi l’SRT e richiama l’endpoint: la versione non riuscita resta nella cronologia e ne viene creata una nuova.

### Controllare il ritmo

Esporta la trascrizione tradotta in JSON con [Esporta trascrizione del progetto](/docs/it/api-reference/project-transcript). Ogni segmento include `finalSpeedFactor`, il rapporto tra il parlato generato e la finestra del segmento. Accorcia i cue che restano sopra circa `1.3`, poi esegui di nuovo il doppiaggio con l'SRT rivisto.

## Flusso di esempio

Un'automazione tipica (per esempio uno scenario n8n o Make) concatena gli endpoint come segue:

1. `POST /v1/projects` con il media, `targetLanguage` e un `originalLanguage` esplicito (solo trascrizione).
2. Interroga `GET /v1/translate/{projectId}/status` finché `transcriptionStatus` è `success`, oppure attendi il webhook `project.created`.
3. `POST /v1/projects/{projectId}/transcript` con `{ "source": "original", "outputFormat": "srt" }` e traduci i cue mantenendo numerazione e timecode.
4. `POST /v1/projects/{projectId}/dub` con l'SRT tradotto.
5. Interroga l'endpoint di stato finché `status` è `success`, oppure attendi `project.translation.completed`.
6. Scarica `translatedVideoUrl` (oppure `lipSync.videoUrl` se è stata richiesta la sincronizzazione labiale).
7. `DELETE /v1/translate/{projectId}` quando gli output sono salvati dalla tua parte.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.voicecheap.ai/v1/projects/project_123/dub" \
    -H "x-api-key: vc_your-api-key" \
    -H "Content-Type: application/json" \
    -d '{
      "targetLanguage": "english",
      "translatedSrt": "1\n00:00:00,000 --> 00:00:02,400\nWelcome to this lesson.\n\n2\n00:00:02,400 --> 00:00:05,100\nToday we talk about fractions.",
      "keepBackgroundMusic": true,
      "subtitles": true,
      "subtitlesSource": "translated"
    }'
  ```

  ```typescript TypeScript theme={null}
  interface DubProjectResponse {
    success: boolean;
    message: string;
    projectId: string;
    workId: string;
    estimatedDuration: number;
  }

  const API_BASE_URL = 'https://api.voicecheap.ai/v1';
  const headers = { 'x-api-key': 'vc_your-api-key', 'Content-Type': 'application/json' };

  async function waitForStatus(projectId: string, isReady: (status: any) => boolean): Promise<any> {
    while (true) {
      const status = await fetch(`${API_BASE_URL}/translate/${projectId}/status`, { headers }).then((response) => response.json());
      if (status.status === 'failed') throw new Error(`${status.error?.code}: ${status.error?.message}`);
      if (isReady(status)) return status;
      await new Promise((resolve) => setTimeout(resolve, 15_000));
    }
  }

  async function dubExistingProject(projectId: string, translatedSrt: string): Promise<string> {
    // 1. The project was created earlier with POST /v1/projects; wait for its transcript.
    await waitForStatus(projectId, (status) => status.transcriptionStatus === 'success');

    // 2. Send the translation you produced from the exported transcript.
    const dubResponse = await fetch(`${API_BASE_URL}/projects/${projectId}/dub`, {
      method: 'POST',
      headers,
      body: JSON.stringify({ targetLanguage: 'english', translatedSrt, keepBackgroundMusic: true }),
    });
    if (!dubResponse.ok) {
      const error = await dubResponse.json();
      throw new Error(`${error.code}: ${error.message}`);
    }
    const { workId } = (await dubResponse.json()) as DubProjectResponse;
    console.log('Dubbing started on work', workId);

    // 3. Wait for the dubbed output.
    const completed = await waitForStatus(projectId, (status) => status.status === 'success');
    return completed.translatedVideoUrl as string;
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  API_BASE_URL = 'https://api.voicecheap.ai/v1'
  HEADERS = {'x-api-key': 'vc_your-api-key'}


  def wait_for_status(project_id, is_ready):
      while True:
          status = requests.get(f'{API_BASE_URL}/translate/{project_id}/status', headers=HEADERS).json()
          if status['status'] == 'failed':
              raise RuntimeError(f"{status['error']['code']}: {status['error']['message']}")
          if is_ready(status):
              return status
          time.sleep(15)


  def dub_existing_project(project_id, translated_srt):
      wait_for_status(project_id, lambda status: status['transcriptionStatus'] == 'success')

      response = requests.post(
          f'{API_BASE_URL}/projects/{project_id}/dub',
          headers=HEADERS,
          json={'targetLanguage': 'english', 'translatedSrt': translated_srt, 'keepBackgroundMusic': True},
      )
      response.raise_for_status()
      print('Dubbing started on work', response.json()['workId'])

      completed = wait_for_status(project_id, lambda status: status['status'] == 'success')
      return completed['translatedVideoUrl']
  ```
</CodeGroup>

## Errori

| Stato | Codice | Descrizione |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Un campo del corpo manca o non è valido (`details` elenca ogni campo) |
| 400 | `INVALID_TRANSLATED_SRT` | translatedSrt non contiene cue SRT validi |
| 400 | `INVALID_BOOLEAN_VALUE` | Un'opzione booleana non è stata inviata come booleano JSON |
| 400 | `INVALID_NUMBER_VALUE` | Un'opzione numerica non è stata inviata come numero JSON |
| 400 | `DURATION_DETECTION_FAILED` | La durata del media salvata del progetto non è disponibile |
| 400 | `VOICE_ID_REQUIRED` | La modalità voci personalizzate è stata selezionata senza un ID voce |
| 400 | `VOICE_ID_NOT_ALLOWED_WITH_CLONING` | Un ID voce è stato combinato con la clonazione vocale |
| 400 | `VOICE_CLONING_SETTINGS_NOT_ALLOWED` | Le impostazioni di clonazione sono state combinate con la modalità voci personalizzate |
| 400 | `TRANSLATION_TIME_SKIP_CONFLICT` | I salti temporali sono in conflitto con un'altra opzione audio |
| 400 | `TRANSLATION_TIME_SKIP_REQUIRES_BACKGROUND` | I salti temporali richiedono audio di sottofondo |
| 400 | `TRANSLATION_TIME_SKIP_OUT_OF_RANGE` | Un salto temporale si estende oltre la durata del file multimediale |
| 400 | `SUBTITLES_NOT_AVAILABLE_FOR_AUDIO` | Sono stati richiesti sottotitoli impressi per l'input audio |
| 400 | `LIPSYNC_NOT_AVAILABLE_FOR_AUDIO` | È stata richiesta la sincronizzazione labiale per l'input audio |
| 400 | `TRANSLATION_TIME_SKIP_NOT_AVAILABLE_FOR_AUDIO` | Sono stati richiesti salti temporali per l'input audio |
| 400 | `LIPSYNC_VIDEO_TOO_LONG` | La sincronizzazione labiale è stata richiesta per file multimediali più lunghi della durata supportata |
| 401 | `MISSING_API_KEY` | La chiave API è richiesta |
| 401 | `INVALID_API_KEY_FORMAT` | La chiave API deve iniziare con `vc_` |
| 401 | `INVALID_API_KEY` | La chiave API fornita non è valida |
| 403 | `SUBSCRIPTION_REQUIRED` | L'accesso API richiede un piano Starter o superiore |
| 403 | `FORBIDDEN` | Non hai il permesso di accedere al progetto |
| 403 | `INSUFFICIENT_CREDITS` | Crediti insufficienti per doppiare questo progetto |
| 403 | `CUSTOM_VOICE_ACCESS_DENIED` | La voce selezionata non è una voce del catalogo né una voce personalizzata salvata dall’account autenticato. |
| 403 | `LIPSYNC_MODE_ACCESS_DENIED` | La modalità di sincronizzazione labiale premium non è disponibile nel piano attuale |
| 404 | `PROJECT_NOT_FOUND` | Il progetto non esiste |
| 409 | `DUB_ONLY_REQUIRES_TRANSCRIPTION` | La trascrizione del progetto è ancora in elaborazione oppure non è riuscita |
| 409 | `TRANSLATION_ALREADY_IN_PROGRESS` | Un doppiaggio è già in corso per questa lingua nel progetto |
| 429 | `RATE_LIMIT_EXCEEDED` | Troppe richieste (limite: 10 richieste al minuto) |
| 429 | `CONCURRENT_TRANSLATION_LIMIT_REACHED` | Limite di traduzioni simultanee dell’account raggiunto; vedi `details.limit` |
| 500 | `INTERNAL_ERROR` | Errore imprevisto del server |

Gli errori di allineamento rilevati durante l'esecuzione (`TRANSLATED_SRT_UNMATCHED_CUES`, `TRANSLATED_SRT_MISSING_SEGMENTS`) sono restituiti dall'endpoint di stato e dal webhook di errore, non da questa richiesta.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.