# Skill: full/translate-fix — "תרגום בקול שלך — נבדק ומתוקן בכל שפה" (Complete video)

Your own video in other languages, in your own cloned voice with your lips redrawn — and every language checked before it reaches anyone. Gemini 3.1 Pro watches the original and the translation as a native editor of that language: the meaning, the punchline, names and numbers, word-for-word wording, mispronounced words, a robotic voice. A language that fails gets a fix round: a corrected script written so a voice cannot misread it, one line per sentence, read by your clone, each line placed where you said the sentence, the lips synced again and checked again. The example is the owner's Hebrew joke in Russian: the first translation broke the punchline («всё», that's all, instead of «все», everyone); the fixed one lands. Only for your own video and voice, or with the speaker's consent.

**Includes:** your own video in other languages · your own cloned voice, the lips redrawn · every language checked by a native editor (meaning, punchline, names and numbers, wording, pronunciation, a robotic voice) · a fix round when it fails: a corrected script, line by line · each line where you said the sentence · a second check before delivery · optional: the kinetic edit
**Built on:** `POST /v1/video/translate` (HeyGen, the speaker's own clone and lip-sync) with its automatic check, `POST /v1/video/review` for the corrected script line by line, and — for a language that fails — the lines in `voiceover` on the original's clock (`/v1/studio/edit`, audio only) and `POST /v1/video/lipsync`
**Price:** 570–1350 credits per finished minute · 30 s ≈ 290–690 credits
**Uses:** `/v1/video/translate` · `/v1/video/review` · `/v1/speech/transcripts` · `/v1/voices` · `/v1/voices/speech` · `/v1/studio/edit` · `/v1/video/lipsync`

Base URL: `https://apihub.co.il` · Auth: `Authorization: Bearer <API key>` · Docs: `/docs`
Send the same `X-Tag: <job name>` header on every call of one video; `GET /v1/usage?tag=<job name>` then
returns exactly what it cost. Times in request bodies are **seconds on the edited (output) timeline**.
Unknown fields are rejected with the name of the right field — read the error instead of guessing.
**Files are kept 24 hours** (renders, uploads, generated clips/images/music) — download the finished video.

**Models.** HeyGen translates (Precision), clones the voice (free) and redraws the lips; Gemini 3.1 Pro checks every language
twice at most (the automatic check inside the translation is free, a standalone one costs the model's call); AssemblyAI gives
the original's sentences; the track is our render. A language that passes the first check costs only its translation.

---

## 1. Translate every language — each one checked by itself

```jsonc
POST /v1/studio/uploads { "filename": "talk.mp4", "content_type": "video/mp4", "size_bytes": <bytes> }        // the original file, never a resized copy
POST /v1/video/translate                                                                                     // x-wait-ms: 110000, then poll GET /v1/executions/{id}
{ "video_url": "<source>", "target_languages": ["ru", "en"], "source_language": "he", "mode": "precision",
  "consent": { "accepted": true, "subject": "self", "basis": "own", "locale": "he" } }                        // review: true is the default
// → versions[]: { language, url, captions_url, review: { status, scores, punchline, issues[], summary, suggested_script } }
```

**Rights first.** Only the speaker's own video and voice, or someone who agreed (`subject: "other"` with their full name) —
the voice is cloned and the lips are redrawn, so the consent is recorded with the job.

**Every language is checked before it is delivered** (free, ≈ 30–90 s): Gemini 3.1 Pro watches the original and the
translation as a native editor of the target language and reports the meaning, the punchline, names and numbers, word-for-
word wording, mispronounced words and a robotic voice — each with its time and a fix. `review.status`:
`passed` → that language is done. `warnings` or `failed` → the fix round below, for that language only.



## 2. The original's sentences (once per video)

```jsonc
POST /v1/speech/transcripts { "audio_url": "<source>", "language_code": "he", "speech_models": ["universal-2"] }   // ≈ 1 credit a minute
GET  /v1/speech/transcripts/{id}/sentences                                                                       // [{ start, end, text }] in ms
```

A sentence of 8 s or more: split it at a comma. The punchline — the last words of a joke — goes on its own line: it gets
its own pause in step 6.

## 3. A script a voice cannot misread

```jsonc
POST /v1/video/review { "original_url": "<source>", "translated_url": "<versions[i].url>", "source_language": "he",
  "target_language": "ru", "review_language": "he", "source_sentences": ["<sentence 1>", "<sentence 2>", …] }   // ≈ 10–30 credits, 30–90 s
// → suggested_script: exactly one line per sentence, line i = sentence i
```

**Your own pass over the script before any voice reads it** — the check is a model; you are the second pair of eyes:
- **The meaning and the numbers.** Every sentence is there; a sum keeps its size. Localise a currency only when the new
  word means the same amount: "50 אגורות" is a tiny coin — in Russian «пятьдесят копеек», never «полтинник» (50 roubles:
  it broke the joke in the example).
- **One reading only.** Words whose meaning hangs on an unwritten stress or letter are rewritten: Russian «все» meaning
  "everyone" → «каждый»; write ё where it belongs.
- **Words the voice gets wrong.** A foreign word or name the voice may stress wrongly ("шекелей") → a word the audience
  knows («сотню»), or a stress mark.
- **Spoken, not translated.** Curses and slang the way a native says them («мудак», «жмот»), not the dubbed-movie form.

## 4. The speaker's voice (once per speaker)

```jsonc
POST /v1/voices { "name": "<speaker>", "audio_url": "<1–3 minutes of his clean speech, mp3>", "language": "he",
  "remove_background_noise": true, "consent": { "accepted": true, "subject": "self", "basis": "own" } }        // → voice id, ready in ~1 min
```

His own videos are the best sample — join two or three into one mp3 (`POST /v1/studio/merge` → `"format": "mp3"`).

## 5. One take per line, in his voice

```jsonc
POST /v1/voices/speech { "text": "<line i>", "voice_id": "<voice id>", "language": "ru" }     // ≈ 0.3 credits a second · → url + words (the last word's end = the line's length)
```

## 6. The track, each line where he said it

No call — the times: `start_i = max(sentence_i.start, end of line i−1 + 0.15 s)`, and **0.6–1.0 s more before the
punchline** (the joke needs the beat). Then the render engine lays the lines on the original's clock, his own speech muted:

```jsonc
POST /v1/studio/edit { "video_url": "<source>", "audio": { "mute": true, "normalize": true },
  "voiceover": [ { "url": "<line 1>", "start": 0.15 }, { "url": "<line 2>", "start": 2.83 }, … ],
  "output": { "format": "mp3" } }                                                                             // 36 s ≈ 7 credits
```

A line that runs long pushes the next ones on; the video stays as long as it was, so his gestures still fall on his words.

## 7. His lips on the new track

```jsonc
POST /v1/video/lipsync { "video_url": "<source>", "audio_url": "<track mp3>", "mode": "precision",
  "consent": { "accepted": true, "subject": "self", "basis": "own" } }                                         // ≈ 11 credits a second · x-wait-ms: 110000, then poll
```

## 8. Check again

`POST /v1/video/review` as in step 3, with `translated_url` = the lip-synced video. `passed`, or `warnings` with only
the delivery left → deliver it with the verdict and the scores. Still `failed` → back to step 3 with the new issues, once
more at most; then deliver the best version and say what is left.

**What a clone cannot do yet.** HeyGen's voice (Starfish) is his timbre (8/10 in the example) but reads flat — no anger,
no comic timing (delivery 4/10). The pause of step 6 and a louder, slightly faster angry line help; real acting needs an
ElevenLabs clone of his voice — `POST /v1/ai/voices/clone` { "name", "audio_urls": [1–3 minutes of him, ideally in the
target language], "consent" } — read by eleven_v4 with direction (`[angry]`, `[deadpan]`): `POST /v1/ai/voice` with that
voice_id and `"model": "eleven_v4"` in step 5, the rest unchanged.

## 9. The edit (optional)

The lip-synced video is a normal source. The plain version — captions of the new language on it, one render:

```jsonc
POST /v1/studio/edit { "video_url": "<the lip-synced video>", "language_code": "ru", "captions": { "style": "classic" },
  "audio": { "normalize": true }, "output": { "aspect_ratio": "9:16", "resolution": "1080", "quality": "high" } }   // ≈ 1 credit a second
```

Or the full look — `/skills/full-kinetic.md` on it (the example: kinetic words, a Veo cut-away on the money, the curse
censored with a soft beep and a ❌ on the mouth, a black card on the punchline, a music bed 20 dB under the voice).

## What the example cost

The owner's 36-second Hebrew joke → Russian in his own voice, 31.9 s after the edit (dev, 30.9.2026):

| Step | Credits |
|---|---|
| Translate (HeyGen Precision) + its check (free) → "failed" | 338 |
| The original's sentences | 2 |
| The check with the sentences → the corrected script | 14 |
| 8 lines in his clone (the clone itself: free) | 22 |
| The track on the Hebrew timing | 7 |
| Lip-sync, Precision | 392 |
| The kinetic edit | 30 |
| **Total** | **805** |

A language that passes the first check costs only the translation (≈ 9.5 credits a second at Precision); the fix round
is mostly the second lip-sync.

Send `x-wait-ms: 110000` to wait for the render in the same call; if the response is still
`processing`, poll `GET /v1/executions/{id}` until `status` is `completed` and read `output.url`.

## Check the bill

`GET /v1/usage?tag=<job name>` — per call, per operation and the total, in credits. Quote that to the
customer, not the estimate above.

## Rules that keep captions readable on every platform

- **Safe zone.** Keep text inside the middle 80% of the frame: `side_margin` ≥ 6 handles the sides; `margin`
  ≥ 12 keeps the bottom clear of the platform UI (username, buttons, progress bar).
- **A line never leaves the frame** — a line too wide for the side margins is set smaller automatically. Do
  not shrink the size yourself, wrap instead (`max_chars_per_line`).
- **Hebrew has no capitals** — keep `uppercase: false`; it only breaks Latin words mixed into a sentence.
- **Fonts.** `GET /v1/studio/fonts` lists the bundled families and which scripts they draw. A font that
  cannot draw the caption's language is swapped and reported in `warnings`.
- The customer's transcript wins: to fix a word, `GET /v1/speech/transcripts/{id}/captions`, edit the text,
  and send the list back as `captions.captions` — timing is kept when the word count is unchanged.
