# Skill: full/simple — "כתוביות, כותרת ומוזיקה" (Complete video)

The simple finished video: Gemini watches the clip and writes a title that stops the scroll and a brief for the music, ElevenLabs makes a track that sits under the voice, and one render burns in the captions, the title and the music. Four calls, about a minute and a half, any caption style and hook effect.

**Includes:** captions synced to the speech · a title for the first seconds, written from the video · background music matched to the mood · one render
**Built on:** hook `marker` ("מרקר", `/skills/hook-marker.md`) + captions `pop` ("פופ", `/skills/captions-pop.md`)
**Price:** 110–120 credits per finished minute · 30 s ≈ 56–62 credits
**Uses:** `/v1/speech/transcripts` · `/v1/ai/text` · `/v1/ai/music` · `/v1/studio/edit`

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.** Gemini 3.5 Flash (`quality: "balanced"`) watches the video and writes two lines — the title and the
music brief; ElevenLabs makes the track. Everything is priced by the video's length: a 30-second video costs about
half of a 60-second one.

---

## 1. Transcribe

```jsonc
POST /v1/studio/uploads { "filename": "clip.mp4", "content_type": "video/mp4", "size_bytes": <bytes> }   // a local file → a url (skip for a public url) · the original file, never a resized copy
POST /v1/speech/transcripts { "audio_url": "<video url>", "language_code": "he" }                       // → transcript_id, text, duration_seconds · 23 s ≈ 1 credit
```

## 2. Gemini watches the video and writes the title and the music brief

```jsonc
POST /v1/ai/text { "quality": "balanced", "json": true, "max_tokens": 800,
  "media": [ { "url": "<video url>", "type": "video", "fps": 1 } ],
  "system": "You write two things for a short vertical video, after watching and hearing it:
             1. hook: the on-screen title for the first 3 seconds, in the video's language — 3–7 words, the boldest
                claim or question in the video, so a scroller stops. Wrap the one word that carries the punch in
                *asterisks*. No emojis, no hashtags, no quotes.
             2. music: a brief for an instrumental track that plays UNDER the voice and fits the mood and pace of what
                is said — one sentence in English: genre, tempo (BPM), energy, and instruments that stay audible under
                speech: a steady light beat (drums or percussion) and a simple melody (piano, plucks, guitar). Never
                pads-only ambient — it vanishes under a voice. No vocals.
             Return { hook, music }",
  "prompt": "TRANSCRIPT (23 s): <text>" }                                                     // Gemini 3.5 Flash ≈ 3 credits, ~5 s
// → { "hook": "למה תמיד נצטרך *לעבוד*?", "music": "A thoughtful lo-fi electronic track with a steady 90 BPM drum beat, warm synth plucks and a subtle bassline, no vocals." }
```

## 3. The music

```jsonc
POST /v1/ai/music { "prompt": "<the music brief>", "duration": <video seconds + 2>, "instrumental": true }   // 25 s ≈ 19 credits, ~10 s
```

## 4. One render

```jsonc
POST /v1/studio/edit               // x-wait-ms: 110000
{
  "video_url": "<video url>", "transcript_id": "<id>",
  "hook": { "text": "למה תמיד נצטרך *לעבוד*?", "start": 0, "duration": 3, "style": "marker" },
  "captions": { "style": "pop" },
  "music": { "url": "<music url>", "volume": 0.3, "duck": false, "fade_in_ms": 500, "fade_out_ms": 1500 },
  "audio": { "normalize": true },
  "output": { "aspect_ratio": "9:16", "resolution": "1080", "fit": "crop", "quality": "high" }
}                                                                                               // 22 s ≈ 22 credits, ~1 min
```

**The music level, measured.** The track is normalised to −18 LUFS before `volume`; at 0.3 it sits about 10 dB under
a phone-recorded voice (−18 LUFS) — heard, never in the way. On the example 0.4 competed with the voice and 0.24 was
lost. Keep `duck` off for a talking head: ducking pushes the bed away completely while someone talks without pauses.
A quieter recording → 0.25; a loud, energetic one → 0.35.

**Change the look.** Any caption style (`/skills/captions-<id>.md`) and any hook effect (`/skills/hook-<id>.md`) —
swap the two `style` values; the price does not change. The example uses captions `pop` and hook `marker`.

**Cut the pauses too (optional).** `POST /v1/studio/remove-silence` first and transcribe the cut instead — one more
render, ≈ 1 credit a second.

## What the example cost and how long it took

A 22-second talking-head clip:

| Step | Credits | Time |
|---|---|---|
| Transcribe (23 s) | 1 | 8 s |
| Gemini: title + music brief | 3 | 5 s |
| Music (25 s) | 19 | 10 s |
| Render (1080p, captions + title + music) | 22 | ~1 min |
| **Total** | **45** | **~1.5 min** |

A minute of video ≈ 110–120 credits: the render ≈ 60, the music ≈ 47, the rest ≈ 5.

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.
