> ## 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.

# Dublar o projeto

> Duble um projeto já transcrito a partir do seu próprio SRT traduzido

# Dublar o projeto

Gere as vozes e misture a saída de um projeto existente a partir de um SRT traduzido que você fornece. A VoiceCheap não traduz nada neste endpoint: sem motor de tradução, sem reformulação SmartSync e sem glossário. Cada cue é falado literalmente no segmento correspondente da transcrição do projeto e depois misturado com o fundo original, as legendas e a sincronização labial opcional, exatamente como uma tradução normal.

Use-o quando a tradução é produzida em outro lugar (um tradutor humano, suas próprias ferramentas, um fluxo de automação) e você precisa da VoiceCheap apenas para gerar as vozes. A execução é assíncrona: consulte [Obter status da tradução](/docs/pt/api-reference/translation-status) ou ouça os [Webhooks](/docs/pt/api-reference/webhooks).

## Pré-requisitos

* O projeto precisa existir e a transcrição precisa estar concluída: crie-o com [Criar projeto](/docs/pt/api-reference/create-project) (somente transcrição) ou [Iniciar Tradução](/docs/pt/api-reference/translate) e aguarde `transcriptionStatus: "success"`.
* O seu SRT precisa cobrir a transcrição do projeto: cada segmento precisa de pelo menos um cue, e cada cue precisa cair sobre um segmento. Exporte a transcrição com [Exportar transcrição do projeto](/docs/pt/api-reference/project-transcript) e traduza-a cue a cue para manter os timecodes.
* A solicitação é cobrada como uma tradução da mesma mídia, com a mesma verificação de créditos. Os modos de sincronização labial acrescentam os créditos extras habituais.

## Limite de Simultaneidade

A criação de projetos, a tradução e a dublagem verificam o limite de traduções ativas da sua conta (no máximo 10, possivelmente menos). Apenas traduções ou dublagens em andamento ocupam vagas; projetos apenas de transcrição não ocupam. Ao atingir o limite, a API retorna `CONCURRENT_TRANSLATION_LIMIT_REACHED` (HTTP 429). O limite aplicado aparece em `details.limit`.

Uma segunda execução para o mesmo projeto e idioma de destino também é recusada enquanto outra estiver em andamento (`TRANSLATION_ALREADY_IN_PROGRESS`, HTTP 409).

## Solicitação

Este endpoint aceita um corpo JSON (`Content-Type: application/json`). Opções booleanas e numéricas são enviadas como valores JSON, não como strings.

### Cabeçalhos

<ParamField header="x-api-key" type="string" required>
  Sua chave de API VoiceCheap. Obtenha uma em [app.voicecheap.ai/page-api](https://app.voicecheap.ai/page-api).
</ParamField>

### Parâmetros de caminho

<ParamField path="projectId" type="string" required>
  O identificador do projeto retornado por [Criar projeto](/docs/pt/api-reference/create-project) ou [Iniciar Tradução](/docs/pt/api-reference/translate).
</ParamField>

### Parâmetros do corpo

<ParamField body="targetLanguage" type="string" required>
  O idioma de `translatedSrt`, em minúsculas, da mesma lista de [Iniciar Tradução](/docs/pt/api-reference/translate). Se o projeto ainda não tiver um trabalho para este idioma, um é criado e o idioma é adicionado ao projeto.
</ParamField>

<ParamField body="translatedSrt" type="string" required>
  O conteúdo SRT final no idioma de destino (número do cue, linha de tempo, texto). Máximo de 1.000.000 de caracteres. Os cues são associados aos segmentos da transcrição pelos timestamps: um cue que começa dentro de 50 ms do início de um segmento é atribuído a esse segmento; caso contrário, ao segmento com o qual mais se sobrepõe. Vários cues no mesmo segmento são unidos com um espaço. O tempo, o locutor e a ordem de cada segmento falado vêm sempre da transcrição do projeto; seus timecodes servem apenas para o emparelhamento.
</ParamField>

<ParamField body="webhookUrl" type="string">
  Um endpoint https que passa a receber os [eventos de webhook](/docs/pt/api-reference/webhooks) deste projeto, substituindo o endpoint configurado na conta.

  **Padrão:** O endpoint já armazenado no projeto e, em seguida, o endpoint de webhook da conta.
</ParamField>

<ParamField body="keepBackgroundMusic" type="boolean">
  Manter o áudio de fundo original (música, ambiente) sob as vozes geradas.

  **Padrão:** `true`
</ParamField>

<ParamField body="keepOriginalVoice" type="boolean">
  Manter o locutor original baixo, por baixo da voz gerada.

  **Padrão:** `false`
</ParamField>

<ParamField body="originalVoiceVolume" type="number">
  Volume da voz original de `1` a `70` quando `keepOriginalVoice` está ativado.

  **Padrão:** `30`
</ParamField>

<ParamField body="voiceMode" type="string">
  Estratégia de voz: `cloning` (clonar as vozes dos falantes do projeto) ou `custom` (usar uma voz do catálogo ou sua voz personalizada salva).

  **Padrão:** `cloning`
</ParamField>

<ParamField body="voiceId" type="string">
  Obrigatório quando `voiceMode` é `custom`. Use um ID de `dubbing_voices_list`: uma voz do catálogo ou uma voz personalizada salva pela conta
  autenticada. A cobrança da equipe não concede acesso às vozes salvas de outros membros.
</ParamField>

<ParamField body="voiceIsolatorOption" type="string">
  Modo de isolamento de voz quando `keepBackgroundMusic` está ativado: `studio` ou `realistic`.

  **Padrão:** `studio`
</ParamField>

<ParamField body="subtitles" type="boolean">
  Gravar legendas no vídeo de saída. Exige um projeto de vídeo.

  **Padrão:** `false`
</ParamField>

<ParamField body="subtitlesSource" type="string">
  Texto das legendas quando `subtitles` está ativado: `translated` (o seu SRT) ou `original` (a transcrição de origem).

  **Padrão:** `translated`
</ParamField>

<ParamField body="lipSyncMode" type="string">
  Executar a sincronização labial quando a dublagem estiver pronta: `standard`, `pro` ou `studio`. As regras de plano, duração e créditos são as mesmas de [Iniciar Tradução](/docs/pt/api-reference/translate). Exige um projeto de vídeo.

  **Padrão:** omita o campo para ignorar a sincronização labial.
</ParamField>

<ParamField body="activeSpeakerDetectionEnabled" type="boolean">
  Ativar a detecção do locutor ativo para a execução de sincronização labial solicitada.

  **Padrão:** `false`
</ParamField>

<ParamField body="voiceCloningSettings" type="object">
  Ajuste fino da clonagem de voz, como objeto JSON com `stability` e `similarity` entre `0` e `1`. Somente com `voiceMode: "cloning"`. Veja [Iniciar Tradução](/docs/pt/api-reference/translate) para a orientação de cada valor.
</ParamField>

<ParamField body="translationTimeSkips" type="array">
  Intervalos do tempo de origem que permanecem no idioma original, como `[{ "startTime": 10.2, "endTime": 12.8 }]`. Exige um projeto de vídeo e `keepBackgroundMusic: true`, não pode ser combinado com `keepOriginalVoice` e não pode sobrepor segmentos da transcrição.
</ParamField>

## Resposta

<ResponseField name="success" type="boolean" required>
  Sempre `true` para solicitações bem-sucedidas.
</ResponseField>

<ResponseField name="message" type="string" required>
  Uma confirmação legível.
</ResponseField>

<ResponseField name="projectId" type="string" required>
  O projeto que está sendo dublado.
</ResponseField>

<ResponseField name="workId" type="string" required>
  O trabalho de tradução usado para `targetLanguage`. Corresponde a `workId` nos endpoints de status, detalhes e transcrição.
</ResponseField>

<ResponseField name="estimatedDuration" type="number" required>
  Estimativa aproximada de processamento em minutos: cinco minutos de processamento por minuto iniciado da mídia de origem.
</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
}
```

## Acompanhar a execução

O projeto muda para o fluxo `translation` assim que a dublagem começa, então [Obter status da tradução](/docs/pt/api-reference/translation-status) acompanha a nova execução: `status` passa de `processing` para `success` (com `translatedVideoUrl` e `translatedAudioUrl`) ou `failed` (com `error`). Os webhooks `project.translation.completed` e `project.translation.failed` são enviados com o mesmo `targetLanguage`. Em [Obter Detalhes do Projeto](/docs/pt/api-reference/project-details), a versão traduzida informa `settings.dubbingMode: "dub-only"` e `settings.smartSync: false`.

As falhas de alinhamento aparecem depois de o pedido POST ser aceite. O endpoint de status devolve `status: "failed"` com `error.code` e `error.message`; o webhook `project.translation.failed` inclui o mesmo código e mensagem. Em `TRANSLATED_SRT_UNMATCHED_CUES`, os números dos cues sem correspondência aparecem na mensagem; em `TRANSLATED_SRT_MISSING_SEGMENTS`, aparecem os índices dos segmentos sem cue. Estas respostas assíncronas não incluem um campo `details` estruturado. Corrija o SRT e chame novamente o endpoint: a versão com falha permanece no histórico e é criada uma nova.

### Verificar o ritmo

Exporte a transcrição traduzida como JSON com [Exportar transcrição do projeto](/docs/pt/api-reference/project-transcript). Cada segmento traz `finalSpeedFactor`, a razão entre a fala gerada e a janela do segmento. Encurte os cues que ficarem acima de cerca de `1.3` e execute a dublagem de novo com o SRT revisado.

## Fluxo de exemplo

Uma automação típica (por exemplo um cenário do n8n ou do Make) encadeia os endpoints assim:

1. `POST /v1/projects` com a mídia, `targetLanguage` e um `originalLanguage` explícito (somente transcrição).
2. Consulte `GET /v1/translate/{projectId}/status` até `transcriptionStatus` ser `success`, ou espere o webhook `project.created`.
3. `POST /v1/projects/{projectId}/transcript` com `{ "source": "original", "outputFormat": "srt" }` e traduza os cues mantendo a numeração e os timecodes.
4. `POST /v1/projects/{projectId}/dub` com o SRT traduzido.
5. Consulte o endpoint de status até `status` ser `success`, ou espere `project.translation.completed`.
6. Baixe `translatedVideoUrl` (ou `lipSync.videoUrl` quando a sincronização labial foi solicitada).
7. `DELETE /v1/translate/{projectId}` quando as saídas estiverem armazenadas do seu lado.

<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>

## Erros

| Status | Código | Descrição |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Um campo do corpo está ausente ou é inválido (`details` lista cada campo) |
| 400 | `INVALID_TRANSLATED_SRT` | translatedSrt não contém cues SRT válidos |
| 400 | `INVALID_BOOLEAN_VALUE` | Uma opção booleana não foi enviada como booleano JSON |
| 400 | `INVALID_NUMBER_VALUE` | Uma opção numérica não foi enviada como número JSON |
| 400 | `DURATION_DETECTION_FAILED` | A duração de mídia armazenada do projeto não está disponível |
| 400 | `VOICE_ID_REQUIRED` | O modo de vozes personalizadas foi selecionado sem um ID de voz |
| 400 | `VOICE_ID_NOT_ALLOWED_WITH_CLONING` | Um ID de voz foi combinado com clonagem de voz |
| 400 | `VOICE_CLONING_SETTINGS_NOT_ALLOWED` | As configurações de clone foram combinadas com o modo de vozes personalizadas |
| 400 | `TRANSLATION_TIME_SKIP_CONFLICT` | Pulos de tempo entram em conflito com outra opção de áudio |
| 400 | `TRANSLATION_TIME_SKIP_REQUIRES_BACKGROUND` | Pulos de tempo requerem áudio de fundo |
| 400 | `TRANSLATION_TIME_SKIP_OUT_OF_RANGE` | Um pulo de tempo se estende além da duração da mídia |
| 400 | `SUBTITLES_NOT_AVAILABLE_FOR_AUDIO` | Legendas embutidas foram solicitadas para entrada de áudio |
| 400 | `LIPSYNC_NOT_AVAILABLE_FOR_AUDIO` | Sincronização labial foi solicitada para entrada de áudio |
| 400 | `TRANSLATION_TIME_SKIP_NOT_AVAILABLE_FOR_AUDIO` | Pulos de tempo foram solicitados para entrada de áudio |
| 400 | `LIPSYNC_VIDEO_TOO_LONG` | Sincronização labial foi solicitada para mídia com duração superior à suportada |
| 401 | `MISSING_API_KEY` | A chave de API é necessária |
| 401 | `INVALID_API_KEY_FORMAT` | A chave de API deve começar com `vc_` |
| 401 | `INVALID_API_KEY` | A chave de API fornecida é inválida |
| 403 | `SUBSCRIPTION_REQUIRED` | O acesso à API requer um plano Starter ou superior |
| 403 | `FORBIDDEN` | Você não tem permissão para acessar o projeto |
| 403 | `INSUFFICIENT_CREDITS` | Créditos insuficientes para dublar este projeto |
| 403 | `CUSTOM_VOICE_ACCESS_DENIED` | A voz selecionada não é uma voz do catálogo nem uma voz personalizada salva pela conta autenticada. |
| 403 | `LIPSYNC_MODE_ACCESS_DENIED` | O modo de sincronização labial premium não está disponível no plano atual |
| 404 | `PROJECT_NOT_FOUND` | O projeto não existe |
| 409 | `DUB_ONLY_REQUIRES_TRANSCRIPTION` | A transcrição do projeto ainda está em processamento ou falhou |
| 409 | `TRANSLATION_ALREADY_IN_PROGRESS` | Já existe uma dublagem em andamento para este idioma no projeto |
| 429 | `RATE_LIMIT_EXCEEDED` | Muitas solicitações (limite: 10 solicitações por minuto) |
| 429 | `CONCURRENT_TRANSLATION_LIMIT_REACHED` | Limite de traduções simultâneas da conta atingido; consulte `details.limit` |
| 500 | `INTERNAL_ERROR` | Erro inesperado do servidor |

Falhas de alinhamento detectadas durante a execução (`TRANSLATED_SRT_UNMATCHED_CUES`, `TRANSLATED_SRT_MISSING_SEGMENTS`) são devolvidas pelo endpoint de status e pelo webhook de falha, não por esta solicitação.


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