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

# Projekt synchronisieren

> Ein bereits transkribiertes Projekt mit Ihrem eigenen übersetzten SRT synchronisieren

# Projekt synchronisieren

Erzeugen Sie die Stimmen und mischen Sie die Ausgabe eines bestehenden Projekts aus einem übersetzten SRT, das Sie bereitstellen. VoiceCheap übersetzt auf diesem Endpunkt nichts: keine Übersetzungs-Engine, keine SmartSync-Umformulierung, kein Glossar. Jeder Cue wird wörtlich auf dem passenden Segment des Projekttranskripts gesprochen und dann mit dem ursprünglichen Hintergrund, den Untertiteln und dem optionalen Lippensync gemischt, genau wie bei einer normalen Übersetzung.

Nutzen Sie ihn, wenn die Übersetzung woanders entsteht (ein menschlicher Übersetzer, Ihre eigenen Werkzeuge, ein Automatisierungsablauf) und Sie VoiceCheap nur für die Stimmenerzeugung brauchen. Der Lauf ist asynchron: fragen Sie [Übersetzungsstatus abrufen](/docs/de/api-reference/translation-status) ab oder hören Sie auf die [Webhooks](/docs/de/api-reference/webhooks).

## Voraussetzungen

* Das Projekt muss existieren und seine Transkription muss abgeschlossen sein: erstellen Sie es mit [Projekt erstellen](/docs/de/api-reference/create-project) (nur Transkription) oder [Übersetzung starten](/docs/de/api-reference/translate) und warten Sie auf `transcriptionStatus: "success"`.
* Ihr SRT muss das Projekttranskript abdecken: jedes Transkriptsegment braucht mindestens einen Cue, und jeder Cue muss auf einem Segment liegen. Exportieren Sie das Transkript mit [Projekttranskript exportieren](/docs/de/api-reference/project-transcript) und übersetzen Sie es Cue für Cue, damit die Zeitcodes erhalten bleiben.
* Die Anfrage wird wie eine Übersetzung desselben Mediums abgerechnet, mit derselben Credit-Prüfung. Lippensync-Modi verbrauchen wie üblich zusätzliche Credits.

## Gleichzeitige Ausführungsgrenze

Projekterstellung, Übersetzung und Vertonung prüfen alle das Limit Ihres Kontos für aktive Übersetzungen (höchstens 10, möglicherweise weniger). Nur laufende Übersetzungs- oder Vertonungsvorgänge belegen Plätze; Projekte mit reiner Transkription nicht. Bei Erreichen des Limits gibt die API `CONCURRENT_TRANSLATION_LIMIT_REACHED` (HTTP 429) zurück. Das geltende Limit steht in `details.limit`.

Ein zweiter Lauf für dasselbe Projekt und dieselbe Zielsprache wird ebenfalls abgelehnt, solange einer läuft (`TRANSLATION_ALREADY_IN_PROGRESS`, HTTP 409).

## Anfrage

Dieser Endpunkt akzeptiert einen JSON-Body (`Content-Type: application/json`). Boolesche und numerische Optionen werden als JSON-Werte gesendet, nicht als Zeichenketten.

### Header

<ParamField header="x-api-key" type="string" required>
  Ihr VoiceCheap API-Schlüssel. Erhalten Sie einen von [app.voicecheap.ai/page-api](https://app.voicecheap.ai/page-api).
</ParamField>

### Pfadparameter

<ParamField path="projectId" type="string" required>
  Die Projektkennung, die [Projekt erstellen](/docs/de/api-reference/create-project) oder [Übersetzung starten](/docs/de/api-reference/translate) zurückgibt.
</ParamField>

### Body-Parameter

<ParamField body="targetLanguage" type="string" required>
  Die Sprache von `translatedSrt`, in Kleinbuchstaben, aus derselben Liste wie [Übersetzung starten](/docs/de/api-reference/translate). Wenn das Projekt noch keine Arbeit für diese Sprache hat, wird eine erstellt und die Sprache dem Projekt hinzugefügt.
</ParamField>

<ParamField body="translatedSrt" type="string" required>
  Der endgültige SRT-Inhalt in der Zielsprache (Cue-Nummer, Zeitzeile, Text). Maximal 1.000.000 Zeichen. Cues werden den Transkriptsegmenten über Zeitstempel zugeordnet: ein Cue, der innerhalb von 50 ms nach einem Segmentstart beginnt, wird diesem Segment zugewiesen, sonst dem Segment mit der größten Überlappung. Mehrere Cues auf einem Segment werden mit einem Leerzeichen verbunden. Zeitpunkt, Sprecher und Reihenfolge jedes gesprochenen Segments kommen immer aus dem Projekttranskript; Ihre Zeitcodes dienen nur der Zuordnung.
</ParamField>

<ParamField body="webhookUrl" type="string">
  Ein https-Endpunkt, der ab jetzt die [Webhook-Ereignisse](/docs/de/api-reference/webhooks) für dieses Projekt empfängt und den auf dem Konto konfigurierten Endpunkt überschreibt.

  **Standard:** Der bereits im Projekt gespeicherte Endpunkt, danach der Webhook-Endpunkt des Kontos.
</ParamField>

<ParamField body="keepBackgroundMusic" type="boolean">
  Die ursprüngliche Hintergrundaufnahme (Musik, Ambiente) unter den erzeugten Stimmen behalten.

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

<ParamField body="keepOriginalVoice" type="boolean">
  Die ursprüngliche Stimme leise unter der erzeugten Stimme behalten.

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

<ParamField body="originalVoiceVolume" type="number">
  Lautstärke der Originalstimme von `1` bis `70`, wenn `keepOriginalVoice` aktiviert ist.

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

<ParamField body="voiceMode" type="string">
  Stimmstrategie: `cloning` (die Sprecher des Projekts klonen) oder `custom` (eine Katalogstimme oder Ihre gespeicherte benutzerdefinierte Stimme verwenden).

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

<ParamField body="voiceId" type="string">
  Erforderlich, wenn `voiceMode` `custom` ist. Verwenden Sie eine ID aus `dubbing_voices_list`: eine Katalogstimme oder eine vom authentifizierten
  Konto gespeicherte benutzerdefinierte Stimme. Die Teamabrechnung gewährt keinen Zugriff auf die gespeicherten Stimmen anderer Mitglieder.
</ParamField>

<ParamField body="voiceIsolatorOption" type="string">
  Sprachisolierung, wenn `keepBackgroundMusic` aktiviert ist: `studio` oder `realistic`.

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

<ParamField body="subtitles" type="boolean">
  Untertitel in das Ausgabevideo einbrennen. Erfordert ein Videoprojekt.

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

<ParamField body="subtitlesSource" type="string">
  Untertiteltext, wenn `subtitles` aktiviert ist: `translated` (Ihr SRT) oder `original` (das Quelltranskript).

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

<ParamField body="lipSyncMode" type="string">
  Lippensync starten, sobald die Synchronisation fertig ist: `standard`, `pro` oder `studio`. Plan-, Dauer- und Credit-Regeln sind dieselben wie bei [Übersetzung starten](/docs/de/api-reference/translate). Erfordert ein Videoprojekt.

  **Standard:** Feld weglassen, um den Lippensync zu überspringen.
</ParamField>

<ParamField body="activeSpeakerDetectionEnabled" type="boolean">
  Aktive-Sprecher-Erkennung für den angeforderten Lippensync-Lauf aktivieren.

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

<ParamField body="voiceCloningSettings" type="object">
  Feineinstellung des Stimmklonens als JSON-Objekt mit `stability` und `similarity` zwischen `0` und `1`. Nur mit `voiceMode: "cloning"`. Hinweise zu jedem Wert stehen bei [Übersetzung starten](/docs/de/api-reference/translate).
</ParamField>

<ParamField body="translationTimeSkips" type="array">
  Zeitbereiche der Quelle, die in der Originalsprache bleiben, als `[{ "startTime": 10.2, "endTime": 12.8 }]`. Erfordert ein Videoprojekt und `keepBackgroundMusic: true`, kann nicht mit `keepOriginalVoice` kombiniert werden und darf Transkriptsegmente nicht überlappen.
</ParamField>

## Antwort

<ResponseField name="success" type="boolean" required>
  Bei erfolgreichen Anfragen immer `true`.
</ResponseField>

<ResponseField name="message" type="string" required>
  Eine lesbare Bestätigung.
</ResponseField>

<ResponseField name="projectId" type="string" required>
  Das Projekt, das synchronisiert wird.
</ResponseField>

<ResponseField name="workId" type="string" required>
  Die Übersetzungsarbeit für `targetLanguage`. Sie entspricht `workId` in den Endpunkten für Status, Details und Transkript.
</ResponseField>

<ResponseField name="estimatedDuration" type="number" required>
  Grobe Verarbeitungsschätzung in Minuten: fünf Minuten Verarbeitung je angefangener Minute des Quellmediums.
</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
}
```

## Den Lauf verfolgen

Das Projekt wechselt in den Workflow `translation`, sobald die Synchronisation startet. [Übersetzungsstatus abrufen](/docs/de/api-reference/translation-status) folgt daher dem neuen Lauf: `status` geht von `processing` zu `success` (mit `translatedVideoUrl` und `translatedAudioUrl`) oder `failed` (mit `error`). Die Webhooks `project.translation.completed` und `project.translation.failed` werden mit derselben `targetLanguage` gesendet. In [Projektdetails abrufen](/docs/de/api-reference/project-details) meldet die übersetzte Version `settings.dubbingMode: "dub-only"` und `settings.smartSync: false`.

Ausrichtungsfehler treten auf, nachdem die POST-Anfrage angenommen wurde. Der Status-Endpunkt gibt `status: "failed"` mit `error.code` und `error.message` zurück; der Webhook `project.translation.failed` enthält denselben Code und dieselbe Nachricht. `TRANSLATED_SRT_UNMATCHED_CUES` nennt die nicht zugeordneten Cue-Nummern in der Nachricht, `TRANSLATED_SRT_MISSING_SEGMENTS` die Segmentindizes ohne Cue. Diese asynchronen Antworten enthalten kein strukturiertes `details`-Feld. Korrigieren Sie die SRT-Datei und rufen Sie den Endpunkt erneut auf: Die fehlgeschlagene Version bleibt im Projektverlauf, und eine neue wird erstellt.

### Tempo prüfen

Exportieren Sie das übersetzte Transkript als JSON mit [Projekttranskript exportieren](/docs/de/api-reference/project-transcript). Jedes Segment trägt `finalSpeedFactor`, das Verhältnis zwischen der erzeugten Sprache und dem Segmentfenster. Kürzen Sie die Cues, die ungefähr über `1.3` liegen, und starten Sie die Synchronisation erneut mit dem überarbeiteten SRT.

## Beispielablauf

Eine typische Automatisierung (zum Beispiel ein n8n- oder Make-Szenario) verkettet die Endpunkte so:

1. `POST /v1/projects` mit dem Medium, `targetLanguage` und einer expliziten `originalLanguage` (nur Transkription).
2. Fragen Sie `GET /v1/translate/{projectId}/status` ab, bis `transcriptionStatus` `success` ist, oder warten Sie auf den Webhook `project.created`.
3. `POST /v1/projects/{projectId}/transcript` mit `{ "source": "original", "outputFormat": "srt" }` und übersetzen Sie die Cues, wobei Nummerierung und Zeitcodes erhalten bleiben.
4. `POST /v1/projects/{projectId}/dub` mit dem übersetzten SRT.
5. Fragen Sie den Status-Endpunkt ab, bis `status` `success` ist, oder warten Sie auf `project.translation.completed`.
6. Laden Sie `translatedVideoUrl` herunter (oder `lipSync.videoUrl`, wenn Lippensync angefordert wurde).
7. `DELETE /v1/translate/{projectId}`, sobald die Ausgaben bei Ihnen gespeichert sind.

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

## Fehler

| Status | Code | Beschreibung |
| - | - | - |
| 400 | `VALIDATION_ERROR` | Ein Body-Feld fehlt oder ist ungültig (`details` listet jedes Feld) |
| 400 | `INVALID_TRANSLATED_SRT` | translatedSrt enthält keine gültigen SRT-Cues |
| 400 | `INVALID_BOOLEAN_VALUE` | Eine boolesche Option wurde nicht als JSON-Boolean gesendet |
| 400 | `INVALID_NUMBER_VALUE` | Eine numerische Option wurde nicht als JSON-Zahl gesendet |
| 400 | `DURATION_DETECTION_FAILED` | Die gespeicherte Mediendauer des Projekts ist nicht verfügbar |
| 400 | `VOICE_ID_REQUIRED` | Der Modus für benutzerdefinierte Stimmen wurde ohne eine Stimmen-ID ausgewählt |
| 400 | `VOICE_ID_NOT_ALLOWED_WITH_CLONING` | Eine Stimmen-ID wurde mit Stimmklonen kombiniert |
| 400 | `VOICE_CLONING_SETTINGS_NOT_ALLOWED` | Klon-Einstellungen wurden mit dem Modus für benutzerdefinierte Stimmen kombiniert |
| 400 | `TRANSLATION_TIME_SKIP_CONFLICT` | Zeitübersprünge stehen im Konflikt mit einer anderen Audio-Option |
| 400 | `TRANSLATION_TIME_SKIP_REQUIRES_BACKGROUND` | Zeitübersprünge erfordern Hintergrundaudio |
| 400 | `TRANSLATION_TIME_SKIP_OUT_OF_RANGE` | Ein Zeitübersprung reicht über die Mediendauer hinaus |
| 400 | `SUBTITLES_NOT_AVAILABLE_FOR_AUDIO` | Eingebrannte Untertitel wurden für Audio-Input angefordert |
| 400 | `LIPSYNC_NOT_AVAILABLE_FOR_AUDIO` | Lippensynchronisation wurde für Audio-Input angefordert |
| 400 | `TRANSLATION_TIME_SKIP_NOT_AVAILABLE_FOR_AUDIO` | Zeitübersprünge wurden für Audio-Input angefordert |
| 400 | `LIPSYNC_VIDEO_TOO_LONG` | Lippensynchronisation wurde für Medien angefordert, die länger als die unterstützte Dauer sind |
| 401 | `MISSING_API_KEY` | API-Schlüssel ist erforderlich |
| 401 | `INVALID_API_KEY_FORMAT` | API-Schlüssel muss mit `vc_` beginnen |
| 401 | `INVALID_API_KEY` | Der bereitgestellte API-Schlüssel ist ungültig |
| 403 | `SUBSCRIPTION_REQUIRED` | API-Zugriff erfordert einen Starter-Plan oder höher |
| 403 | `FORBIDDEN` | Sie haben keine Berechtigung, auf das Projekt zuzugreifen |
| 403 | `INSUFFICIENT_CREDITS` | Nicht genügend Credits, um dieses Projekt zu synchronisieren |
| 403 | `CUSTOM_VOICE_ACCESS_DENIED` | Die ausgewählte Stimme ist weder eine Katalogstimme noch eine vom authentifizierten Konto gespeicherte benutzerdefinierte Stimme. |
| 403 | `LIPSYNC_MODE_ACCESS_DENIED` | Der Premium-Lippensynchronisationsmodus ist im aktuellen Plan nicht verfügbar |
| 404 | `PROJECT_NOT_FOUND` | Das Projekt existiert nicht |
| 409 | `DUB_ONLY_REQUIRES_TRANSCRIPTION` | Die Projekttranskription wird noch verarbeitet oder ist fehlgeschlagen |
| 409 | `TRANSLATION_ALREADY_IN_PROGRESS` | Für diese Sprache läuft im Projekt bereits eine Synchronisation |
| 429 | `RATE_LIMIT_EXCEEDED` | Zu viele Anfragen (Limit: 10 Anfragen pro Minute) |
| 429 | `CONCURRENT_TRANSLATION_LIMIT_REACHED` | Kontolimit für gleichzeitige Übersetzungen erreicht; siehe `details.limit` |
| 500 | `INTERNAL_ERROR` | Unerwarteter Serverfehler |

Ausrichtungsfehler, die während der Ausführung erkannt werden (`TRANSLATED_SRT_UNMATCHED_CUES`, `TRANSLATED_SRT_MISSING_SEGMENTS`), liefert der Status-Endpunkt und der fehlgeschlagene Webhook, nicht diese Anfrage.


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