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

# Project nasynchroniseren

> Nasynchroniseer een al getranscribeerd project met uw eigen vertaalde SRT

# Project nasynchroniseren

Genereer de stemmen en mix de uitvoer van een bestaand project vanuit een vertaalde SRT die u aanlevert. VoiceCheap vertaalt niets op dit endpoint: geen vertaalengine, geen SmartSync-herformulering, geen woordenlijst. Elke cue wordt letterlijk ingesproken op het bijbehorende segment van de projecttranscriptie en daarna gemixt met de oorspronkelijke achtergrond, de ondertitels en optionele lipsync, net als een gewone vertaling.

Gebruik het wanneer de vertaling elders ontstaat (een menselijke vertaler, uw eigen tooling, een automatiseringsflow) en u VoiceCheap alleen nodig hebt voor stemgeneratie. De uitvoering is asynchroon: poll [Vertaalstatus ophalen](/docs/nl/api-reference/translation-status) of luister naar de [Webhooks](/docs/nl/api-reference/webhooks).

## Vereisten

* Het project moet bestaan en de transcriptie moet voltooid zijn: maak het aan met [Project aanmaken](/docs/nl/api-reference/create-project) (alleen transcriptie) of [Vertaling starten](/docs/nl/api-reference/translate), en wacht op `transcriptionStatus: "success"`.
* Uw SRT moet de projecttranscriptie dekken: elk transcriptsegment heeft minstens één cue nodig, en elke cue moet op een segment vallen. Exporteer de transcriptie met [Projecttranscriptie exporteren](/docs/nl/api-reference/project-transcript) en vertaal die cue voor cue om de tijdcodes te behouden.
* Het verzoek wordt afgerekend als een vertaling van hetzelfde medium, met dezelfde creditcontrole. Lipsync-modi voegen hun gebruikelijke extra credits toe.

## Gelijktijdigheidslimiet

Projectaanmaak, vertaling en nasynchronisatie controleren allemaal de limiet van uw account voor actieve vertalingen (maximaal 10, mogelijk lager). Alleen lopende vertaal- of nasynchronisatietaken nemen plaatsen in; projecten met alleen transcriptie doen dat niet. Bij het bereiken van de limiet retourneert de API `CONCURRENT_TRANSLATION_LIMIT_REACHED` (HTTP 429). De toegepaste limiet staat in `details.limit`.

Een tweede uitvoering voor hetzelfde project en dezelfde doeltaal wordt ook geweigerd zolang er al een loopt (`TRANSLATION_ALREADY_IN_PROGRESS`, HTTP 409).

## Verzoek

Dit endpoint accepteert een JSON-body (`Content-Type: application/json`). Booleaanse en numerieke opties worden als JSON-waarden verzonden, niet als tekenreeksen.

### Headers

<ParamField header="x-api-key" type="string" required>
  Uw VoiceCheap API-sleutel. Verkrijg er een via [app.voicecheap.ai/page-api](https://app.voicecheap.ai/page-api).
</ParamField>

### Padparameters

<ParamField path="projectId" type="string" required>
  De projectidentificatie die [Project aanmaken](/docs/nl/api-reference/create-project) of [Vertaling starten](/docs/nl/api-reference/translate) teruggeeft.
</ParamField>

### Body-parameters

<ParamField body="targetLanguage" type="string" required>
  De taal van `translatedSrt`, in kleine letters, uit dezelfde lijst als [Vertaling starten](/docs/nl/api-reference/translate). Als het project nog geen werk voor deze taal heeft, wordt er een gemaakt en wordt de taal aan het project toegevoegd.
</ParamField>

<ParamField body="translatedSrt" type="string" required>
  De definitieve SRT-inhoud in de doeltaal (cuenummer, tijdregel, tekst). Maximaal 1.000.000 tekens. Cues worden op tijdstempels aan transcriptsegmenten gekoppeld: een cue die binnen 50 ms na het begin van een segment start, wordt aan dat segment toegewezen, anders aan het segment waarmee hij het meest overlapt. Meerdere cues op één segment worden met een spatie samengevoegd. Timing, spreker en volgorde van elk ingesproken segment komen altijd uit de projecttranscriptie; uw tijdcodes dienen alleen voor de koppeling.
</ParamField>

<ParamField body="webhookUrl" type="string">
  Een https-endpoint dat vanaf nu de [webhookgebeurtenissen](/docs/nl/api-reference/webhooks) voor dit project ontvangt en het op het account ingestelde endpoint overschrijft.

  **Standaard:** Het endpoint dat al op het project is opgeslagen, daarna het webhookendpoint van het account.
</ParamField>

<ParamField body="keepBackgroundMusic" type="boolean">
  De oorspronkelijke achtergrondaudio (muziek, ambiance) onder de gegenereerde stemmen behouden.

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

<ParamField body="keepOriginalVoice" type="boolean">
  De oorspronkelijke spreker zacht onder de gegenereerde stem houden.

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

<ParamField body="originalVoiceVolume" type="number">
  Volume van de oorspronkelijke stem van `1` tot `70` wanneer `keepOriginalVoice` is ingeschakeld.

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

<ParamField body="voiceMode" type="string">
  Stemstrategie: `cloning` (de sprekers van het project klonen) of `custom` (een catalogusstem of je opgeslagen aangepaste stem gebruiken).

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

<ParamField body="voiceId" type="string">
  Vereist wanneer `voiceMode` `custom` is. Gebruik een ID uit `dubbing_voices_list`: een catalogusstem of een aangepaste stem die door het
  geauthenticeerde account is opgeslagen. Teamfacturering geeft geen toegang tot de opgeslagen stemmen van andere leden.
</ParamField>

<ParamField body="voiceIsolatorOption" type="string">
  Stemisolatiemodus wanneer `keepBackgroundMusic` is ingeschakeld: `studio` of `realistic`.

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

<ParamField body="subtitles" type="boolean">
  Ondertitels in de uitvoervideo branden. Vereist een videoproject.

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

<ParamField body="subtitlesSource" type="string">
  Ondertiteltekst wanneer `subtitles` is ingeschakeld: `translated` (uw SRT) of `original` (het brontranscript).

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

<ParamField body="lipSyncMode" type="string">
  Lipsync starten zodra de nasynchronisatie klaar is: `standard`, `pro` of `studio`. De regels voor abonnement, duur en credits zijn dezelfde als bij [Vertaling starten](/docs/nl/api-reference/translate). Vereist een videoproject.

  **Standaard:** laat het veld weg om lipsync over te slaan.
</ParamField>

<ParamField body="activeSpeakerDetectionEnabled" type="boolean">
  Detectie van de actieve spreker inschakelen voor de gevraagde lipsync-run.

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

<ParamField body="voiceCloningSettings" type="object">
  Fijnafstemming van stemklonen, als JSON-object met `stability` en `similarity` tussen `0` en `1`. Alleen met `voiceMode: "cloning"`. Zie [Vertaling starten](/docs/nl/api-reference/translate) voor uitleg bij elke waarde.
</ParamField>

<ParamField body="translationTimeSkips" type="array">
  Bron-tijdbereiken die in de oorspronkelijke taal blijven, als `[{ "startTime": 10.2, "endTime": 12.8 }]`. Vereist een videoproject en `keepBackgroundMusic: true`, kan niet worden gecombineerd met `keepOriginalVoice` en mag transcriptsegmenten niet overlappen.
</ParamField>

## Antwoord

<ResponseField name="success" type="boolean" required>
  Altijd `true` bij geslaagde verzoeken.
</ResponseField>

<ResponseField name="message" type="string" required>
  Een leesbare bevestiging.
</ResponseField>

<ResponseField name="projectId" type="string" required>
  Het project dat wordt genasynchroniseerd.
</ResponseField>

<ResponseField name="workId" type="string" required>
  Het vertaalwerk dat voor `targetLanguage` wordt gebruikt. Het komt overeen met `workId` in de endpoints voor status, details en transcriptie.
</ResponseField>

<ResponseField name="estimatedDuration" type="number" required>
  Ruwe verwerkingsschatting in minuten: vijf minuten verwerking per begonnen minuut bronmedia.
</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
}
```

## De uitvoering volgen

Het project schakelt over naar de workflow `translation` zodra de nasynchronisatie start, dus [Vertaalstatus ophalen](/docs/nl/api-reference/translation-status) volgt de nieuwe run: `status` gaat van `processing` naar `success` (met `translatedVideoUrl` en `translatedAudioUrl`) of `failed` (met `error`). De webhooks `project.translation.completed` en `project.translation.failed` worden verzonden met dezelfde `targetLanguage`. In [Projectdetails ophalen](/docs/nl/api-reference/project-details) meldt de vertaalde versie `settings.dubbingMode: "dub-only"` en `settings.smartSync: false`.

Uitlijningsfouten verschijnen nadat het POST-verzoek is geaccepteerd. Het statusendpoint geeft `status: "failed"` met `error.code` en `error.message` terug; de `project.translation.failed`-webhook bevat dezelfde code en melding. Bij `TRANSLATED_SRT_UNMATCHED_CUES` staan de niet gekoppelde cuenummers in de melding, bij `TRANSLATED_SRT_MISSING_SEGMENTS` de segmentindexen zonder cue. Deze asynchrone antwoorden bevatten geen gestructureerd `details`-veld. Corrigeer de SRT en roep het endpoint opnieuw aan: de mislukte versie blijft in de projectgeschiedenis en er wordt een nieuwe gemaakt.

### Het tempo controleren

Exporteer het vertaalde transcript als JSON met [Projecttranscriptie exporteren](/docs/nl/api-reference/project-transcript). Elk segment bevat `finalSpeedFactor`, de verhouding tussen de gegenereerde spraak en het segmentvenster. Kort de cues in die ongeveer boven `1.3` uitkomen en start de nasynchronisatie opnieuw met de herziene SRT.

## Voorbeeldflow

Een typische automatisering (bijvoorbeeld een n8n- of Make-scenario) koppelt de endpoints als volgt:

1. `POST /v1/projects` met het medium, `targetLanguage` en een expliciete `originalLanguage` (alleen transcriptie).
2. Poll `GET /v1/translate/{projectId}/status` tot `transcriptionStatus` `success` is, of wacht op de webhook `project.created`.
3. `POST /v1/projects/{projectId}/transcript` met `{ "source": "original", "outputFormat": "srt" }` en vertaal de cues met behoud van nummering en tijdcodes.
4. `POST /v1/projects/{projectId}/dub` met de vertaalde SRT.
5. Poll het statusendpoint tot `status` `success` is, of wacht op `project.translation.completed`.
6. Download `translatedVideoUrl` (of `lipSync.videoUrl` wanneer lipsync is aangevraagd).
7. `DELETE /v1/translate/{projectId}` zodra de uitvoer aan uw kant is opgeslagen.

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

## Fouten

| Status | Code | Beschrijving |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Een bodyveld ontbreekt of is ongeldig (`details` vermeldt elk veld) |
| 400 | `INVALID_TRANSLATED_SRT` | translatedSrt bevat geen geldige SRT-cues |
| 400 | `INVALID_BOOLEAN_VALUE` | Een booleaanse optie is niet als JSON-boolean verzonden |
| 400 | `INVALID_NUMBER_VALUE` | Een numerieke optie is niet als JSON-getal verzonden |
| 400 | `DURATION_DETECTION_FAILED` | De opgeslagen mediaduur van het project is niet beschikbaar |
| 400 | `VOICE_ID_REQUIRED` | De modus voor aangepaste stemmen werd geselecteerd zonder een stem-ID |
| 400 | `VOICE_ID_NOT_ALLOWED_WITH_CLONING` | Een stem-ID werd gecombineerd met stemklonen |
| 400 | `VOICE_CLONING_SETTINGS_NOT_ALLOWED` | Klooninstellingen werden gecombineerd met de modus voor aangepaste stemmen |
| 400 | `TRANSLATION_TIME_SKIP_CONFLICT` | Tijdoverslaan conflicteert met een andere audio-optie |
| 400 | `TRANSLATION_TIME_SKIP_REQUIRES_BACKGROUND` | Tijdoverslaan vereist achtergrondaudio |
| 400 | `TRANSLATION_TIME_SKIP_OUT_OF_RANGE` | Een tijdoverslag valt buiten de mediaduur |
| 400 | `SUBTITLES_NOT_AVAILABLE_FOR_AUDIO` | Ingebrande ondertitels werden aangevraagd voor audio-input |
| 400 | `LIPSYNC_NOT_AVAILABLE_FOR_AUDIO` | Lipsynchronisatie werd aangevraagd voor audio-input |
| 400 | `TRANSLATION_TIME_SKIP_NOT_AVAILABLE_FOR_AUDIO` | Tijdoverslaan werd aangevraagd voor audio-input |
| 400 | `LIPSYNC_VIDEO_TOO_LONG` | Lipsynchronisatie werd aangevraagd voor media die langer is dan de ondersteunde duur |
| 401 | `MISSING_API_KEY` | API-sleutel is vereist |
| 401 | `INVALID_API_KEY_FORMAT` | API-sleutel moet beginnen met `vc_` |
| 401 | `INVALID_API_KEY` | De verstrekte API-sleutel is ongeldig |
| 403 | `SUBSCRIPTION_REQUIRED` | API-toegang vereist een Starter-abonnement of hoger |
| 403 | `FORBIDDEN` | U heeft geen toestemming om toegang te krijgen tot het project |
| 403 | `INSUFFICIENT_CREDITS` | Onvoldoende credits om dit project te nasynchroniseren |
| 403 | `CUSTOM_VOICE_ACCESS_DENIED` | De geselecteerde stem is geen catalogusstem of aangepaste stem die door het geauthenticeerde account is opgeslagen. |
| 403 | `LIPSYNC_MODE_ACCESS_DENIED` | De premium lipsynchronisatie-modus is niet beschikbaar in het huidige abonnement |
| 404 | `PROJECT_NOT_FOUND` | Het project bestaat niet |
| 409 | `DUB_ONLY_REQUIRES_TRANSCRIPTION` | De projecttranscriptie wordt nog verwerkt of is mislukt |
| 409 | `TRANSLATION_ALREADY_IN_PROGRESS` | Er loopt al een nasynchronisatie voor deze taal in het project |
| 429 | `RATE_LIMIT_EXCEEDED` | Te veel verzoeken (limiet: 10 verzoeken per minuut) |
| 429 | `CONCURRENT_TRANSLATION_LIMIT_REACHED` | Accountlimiet voor gelijktijdige vertalingen bereikt; zie `details.limit` |
| 500 | `INTERNAL_ERROR` | Onverwachte serverfout |

Uitlijningsfouten die tijdens de run worden vastgesteld (`TRANSLATED_SRT_UNMATCHED_CUES`, `TRANSLATED_SRT_MISSING_SEGMENTS`) worden teruggegeven door het statusendpoint en de mislukte webhook, niet door dit verzoek.


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