# Skill: full/stock-faceless — "סרטון בלי פנים מסטוק" (Complete video)

A faceless video for the price of an edit: the voice goes on — the speaker's own, or a script read by ElevenLabs — while stock footage and photos fill the screen, a new shot every couple of seconds and a new scene with every idea. Gemini Flash-Lite splits the words into scenes and writes the searches, every candidate is scored and checked, the shots cover the whole video with no gap, and the kinetic words, a hook, title cards, sound design and a beat go on top — one render. Covering a minute with Veo would take fifteen generated clips. Photos and videos provided by Pexels.

**Includes:** stock video clips (Pexels) over the whole video, a new shot every ~2.4 s · a scene per idea, chosen and checked by a cheap model · the speaker's own voice — or an ElevenLabs narration · every word on screen as it is said · hook · black title cards · sound design · music under the voice · a licence per shot
**Built on:** kinetic `texts[]` (effects `words`, `punch`, `blur_in`, `rise`, `glitch`) laid out by `POST /v1/studio/kinetic` + stock footage from `POST /v1/stock/broll-plan` — no caption line; the nearest single looks are hook `words` and captions `volt`
**Price:** 115–128 credits per finished minute · 30 s ≈ 62–70 credits
**Uses:** `/v1/speech/transcripts` · `/v1/studio/remove-silence` · `/v1/studio/kinetic` · `/v1/ai/text` · `/v1/ai/sound-effects` · `/v1/ai/music` · `/v1/stock/broll-plan` · `/v1/studio/edit` · `/v1/ai/voice`

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 — the cheapest that do the job, and no generated video.** AssemblyAI Universal-2 transcribes twice, Gemini 3.1
Flash-Lite picks the moments of the words and — inside `POST /v1/stock/broll-plan` — the stock moments and a thumbnail check,
ElevenLabs makes four short sounds and a music bed; the footage is free stock (Pexels, Pixabay, CC0 collections). Everything is
priced by the video's length.

---

## 1. Transcribe the video (once)

```jsonc
POST /v1/studio/uploads { "filename": "clip.mp4", "content_type": "video/mp4", "size_bytes": <bytes> }   // a local file → output.url (skip for a public link) · the original file, never a resized copy
POST /v1/speech/transcripts { "audio_url": "<video url>", "language_code": "he", "speech_models": ["universal-2"] }
// → T0, the video's words · Universal-2 · 64 s ≈ 1 credit
// optional — the music level: a WAV of the voice for the planner to measure (`cut_audio_url`); without it the music sits at 0.3
POST /v1/studio/convert { "video_url": "<video url>", "output": { "format": "wav" } }                      // x-wait-ms: 90000 · ≈ 0.15 credits a second
```

**One transcript, on the video's own clock.** Every element the planner writes is anchored to a word — `at` a word's
id (w0001…) or `during` a stretch of them — and the render does the rest: it finds the pauses in the sound itself
(`remove_silence`, the same numbers give the same cut every time), cuts them, and puts each text, zoom, sticker and
sound on the exact output frame its word lands on. Nothing is timed on a guessed cut clock, so the cut audio is never
transcribed a second time and there is nothing to put back from a reference transcript. The render's answer reports
where every element landed (`elements`: exact / moved / lost — a word that was cut moves its element to the next
kept word of the phrase; one with nothing left to hold on to is dropped and named).

**Why a WAV (optional).** The planner measures the voice's loudness in it (`cut_audio_url`) and sets the music
≈ 10 dB under the voice — a loud car recording (−12 LUFS) needs twice the music volume of a quiet one (−18).

**Everything below is timed on the cut video's clock.**

**Two ways in.** A) *The speaker's own voice* — a talking-head recording whose face is never shown: steps 1–7 below.
B) *A narration* — no video at all, a script read by ElevenLabs: the variant after step 7.

## 2. The first plan — the numbered words and the length

```jsonc
POST /v1/studio/kinetic
{ "video_url": "<video url>", "transcript_id": "<T0>", "cut": { "from": "audio", "min_pause_ms": 200, "padding_ms": 70 },
  "cut_audio_url": "<the wav's url>" }                                   // cut_audio_url optional (the music level) · 1 credit
// → output.words (numbered, with ids, the video's clock, seconds), output.summary.source_seconds, output.warnings
//   every element of output.edit is anchored to a word (at / during); the render cuts the pauses around them
```

## 3. Gemini Flash-Lite picks the moments of the words

```jsonc
POST /v1/ai/text                           // Gemini 3.1 Flash-Lite ≈ 1 credit
{ "quality": "fast", "json": true, "max_tokens": 3000, "temperature": 0.4,
  "system": "<the kinetic picker brief — /skills/full-kinetic.md, step 3, verbatim>",
  "prompt": "The video is <summary.source_seconds> s (its pauses will be cut). Numbered words:\n0:אין 1:כזה 2:דבר, 3:אני …",
  "media": [ { "url": "<video url>", "type": "video", "fps": 0.5 } ] }
```

Keep the corrections that repair a real mistake, drop those that change the speaker's own style (the kinetic skill
explains). Use the emphasis and the title card; stickers are optional here (the footage already illustrates).

## 4. The assets — in parallel, each made once

```jsonc
POST /v1/ai/sound-effects { "text": "fast short airy whoosh swipe transition, clean, no reverb tail", "duration": 0.6, "prompt_influence": 0.5 }   // ≈ 1 credit — also the whoosh into every stock shot
POST /v1/ai/sound-effects { "text": "short soft bubble pop click for a sticker appearing, clean", "duration": 0.5, "prompt_influence": 0.5 }
POST /v1/ai/sound-effects { "text": "short digital glitch stutter burst, electronic, clean", "duration": 0.5, "prompt_influence": 0.5 }
POST /v1/ai/sound-effects { "text": "one second tension riser swell that stops abruptly, no hit", "duration": 1.0, "prompt_influence": 0.5 }
POST /v1/stock/icon { "icon": "fluent-emoji-flat:<sticker icon>", "size": 512, "padding": 4 }   // one per sticker · free
POST /v1/ai/music { "prompt": "<picks.music>", "duration": <ceil(summary.output_seconds + 1)>, "instrumental": true }   // ≈ 0.77 credits a second
```

## 5. The final kinetic plan

```jsonc
POST /v1/studio/kinetic
{ …the body of step 2…, "corrections": […], "emphasis": […], "scenes": […], "stickers": [ { "word": 17, "url": "<icon png>" }, … ],
  "sounds": { "whoosh": "<mp3>", "pop": "<mp3>", "glitch": "<mp3>", "riser": "<mp3>" }, "music": { "url": "<music mp3>" } }
// → output.edit — the complete render body; output.words — the same numbered words
```

## 6. The stock footage over the whole video

```jsonc
POST /v1/stock/broll-plan
{ "style": "faceless", "shot_seconds": 2.4,
  "words": <output.words of step 5>, "duration": <summary.output_seconds>,
  "edit": <output.edit of step 5>,
  "sounds": { "whoosh": "<the whoosh mp3>" },
  "topic": "<one line: what the video is about>" }        // ≈ 7 credits for a minute, ≈ 25 s · an advert: add "context": "ad"
// → output.edit (ready: the zooms are gone — there is no face to push in on), output.shots (one per shot), output.warnings
```

- Gemini Flash-Lite splits the words into scenes (one idea each, every 3–7 s) with a search per scene; every scene is cut
  into shots of ≈ `shot_seconds`, each a different file, hard cuts on the scene's words, a whoosh on every new scene.
- The shots cover the whole video with no gap — a scene whose search finds nothing borrows a picture from the scene next
  to it (`warnings` says so), so the face is never seen. The black title cards and the stickers stay on top.
- Portrait footage is preferred (it fills the phone screen); a landscape picture is centre-cropped, and the thumbnail
  check is told so. A light band (22 % black) runs under the words for the whole video (`scrim: false` removes it).

## 7. One render

```jsonc
POST /v1/studio/edit <output.edit of step 6>           // x-wait-ms: 90000, then poll GET /v1/executions/{id}
```

## B) From a narration instead of a recording

```jsonc
POST /v1/ai/voice { "text": "<the script>", "voice_id": "<GET /v1/ai/voices>", "timestamps": true, "mood": "<the delivery, e.g. warm explainer>" }   // ≈ 30 credits per 1,000 characters (eleven_v4, the newest; Hebrew is directed for you: tags, niqqud, stability)
// → output.url (mp3), output.duration_seconds, output.words [ { "text", "start", "end" } ] (seconds)
POST /v1/studio/kinetic { "video_url": "https://media.gpt.org.il/samples/canvas-9x16-black-15min.mp4",
  "words": <output.words with start/end × 1000 — ms>, "cut": false,
  "source": { "duration": <duration_seconds>, "fps": 30 }, …the picks and assets of steps 3–4 }
POST /v1/stock/broll-plan { "style": "faceless", "words": <kinetic output.words>, "edit": <kinetic output.edit>,
  "voice": { "url": "<the mp3>", "seconds": <duration_seconds> }, … }    // adds the narration and trims the render to it
POST /v1/studio/edit <output.edit>
```

The canvas is a silent black 9:16 video (15 minutes) the stock covers completely; the narration is the only voice.
No transcription and no silence pass are needed — the voice comes with its word timings.

## How a shot is chosen (`POST /v1/stock/broll-plan`)

1. **Moments.** Gemini 3.1 Flash-Lite reads the numbered words and names the moments with an English search each
   (`query`), a broader second one (`alt`) and the visible subject in one or two nouns (`short`) — for the sources that
   match words exactly. Or send your own `moments` and no model is asked.
2. **Search.** Pexels and Pixabay get the full search (they rank by meaning; portrait first for a 9:16 video); Commons
   and Openverse get the nouns, widened step by step until there are enough results. Answers are cached for a day
   (Pexels allows 200 requests an hour: a cutaway plan makes ≈ 10, a faceless minute ≈ 25).
3. **Score** (0–1): the search words in the title and tags (40 %), the shape against the frame (20 % — a portrait shot
   fills 9:16, a landscape one goes in the split band), the pixels against the crop (15 % — more than 2.2× enlargement is
   refused), a clip before a photo (15 %), the source (10 %). A clip shorter than its slot, a ShareAlike or
   NonCommercial file, or one that needs a credit when none is allowed is never a candidate.
4. **Check.** The best 3–6 of every moment go to Gemini Flash-Lite as small thumbnails with the line that is said:
   0–10 each, text / watermark / logo / screenshot / collage / blur = 0–2 = vetoed. Final = 55 % check + 45 % score.
5. **Copy.** Each chosen file is copied to our storage (24 hours), the next candidate if a download fails.

The answer: `edit` (your body with the shots merged in — stock under the stickers, a whoosh 0.25 s before every
cutaway, credit lines if any), `overlays` on their own, `shots` (what was said, the search, the file, the licence, the
score and the check), `summary`, `picker` (the model's moments) and `warnings`. One call: cutaways ≈ 10 s and 2–3 credits, a faceless minute
≈ 20–30 s and 6–7 credits — the price is the Gemini calls' own cost; the searches are free.

The brief the model gets for the scenes (for reference — the endpoint sends it itself):

```text
You choose the pictures for a FACELESS vertical video: the speaker is never seen — while the voice goes on, stock footage and photos fill the whole screen, a new shot every 2–3 seconds. You get the transcript as numbered words (number:word@seconds). Return JSON only:
{"scenes":[{"word": n, "query": "…", "alt": "…", "short": "…", "tone": "neutral"}]}
RULES
- one scene per idea, a new one every 3–7 seconds — about 12 scenes for 58 s. The first scene starts at word 0; each next one at the word where a new idea starts, in order.
- a scene shows what its words are about, literally when the words name a thing, as a visual metaphor when they are abstract.
- prefer what a camera films — people, hands, objects, places, actions — over screens and interfaces (what a screen shows is rarely in stock and never readable).
- query: ENGLISH, 2–5 words, a generic filmable stock scene — a subject plus an action or setting ("woman scrolling phone feed", "video editing timeline on laptop", "man relaxing in hammock"). Stock libraries have no brands, apps, logos, company or people's names, screenshots or text: turn such a line into the scene it describes ("uploads to Instagram automatically" → "phone posting to social media"; "an AI agent" → "robot assistant working on laptop").
- alt: a second, broader query for the same moment, with different words.
- short: 1–3 comma-separated alternatives, each the main VISIBLE OBJECT or place in 1–2 English NOUNS — never a verb, an idea, or just "person" / "man" / "woman" ("smartphone, phone in hand", "laptop", "hammock", "robot", "office desk") — they are searched in photo titles, word for word.
- tone: "negative" when the line is about something bad — failure, a scam or fraud, loss, debt, fear, pain, illness, crime, anger, sadness, a mistake; else "neutral" or "positive". A negative line is illustrated with objects, places or hands, never a person's face (real people in stock footage must not be shown in a bad light).
- vary the pictures: never the same query twice; mix people, hands, objects and places.
```

## Where the footage comes from, and the licences

**The licence rule (since 28.9.2026).** What the plan inserts on its own is **CC0 only** by default — photos and video on
Wikimedia Commons marked CC0 and Openverse CC0 — and a shot goes in only with its licence record (the source, the file
at the source, its page, the licence URL), which comes back in `output.shots` (`license`, `license_name`,
`license_url`, `source_url`, `page_url`). CC0 means no credit and no on-video marking, commercial use allowed.
Pexels and Pixabay (below) are used only where the server's rule allows more than CC0 (`output.summary.license_rule`
says which rule ran): the examples on this page were made on 27.9, before the rule, with Pexels.

**Photos and videos provided by [Pexels](https://www.pexels.com)** (when the server's rule allows them).

| Source | What | Licence | Needs |
|---|---|---|---|
| **Pexels** | stock video (portrait 1080p and more) and photos | Pexels licence — commercial use, edits allowed, no credit required | the server's `PEXELS_API_KEY` (set on dev) |
| **Pixabay** | stock video and photos | Pixabay content licence — commercial use, no credit | the server's `PIXABAY_API_KEY` (not set yet) |
| **Wikimedia Commons, stock** | ~37,000 photographs Commons hosts from Unsplash and Pixabay (their CC0 years) | CC0 — no credit | nothing |
| **Wikimedia Commons, CC0** | photos and ~10,500 video clips whose licence statement and file page say CC0 | CC0 — no credit | nothing (the default rule) |
| **Openverse** | openly licensed photos (StockSnap, rawpixel, Flickr…) | CC0 (the default rule) / public domain (CC BY with `attribution: "any"`) | nothing |
| **Wikimedia Commons, video** | CC0 / public-domain / CC BY clips (documentary more than B-roll) | as marked per file | only with `kind: "video"` and no Pexels / Pixabay key |

**Pexels and Pixabay are used only inside the edit.** Under their API terms the plan copies the chosen files for this
render (they expire with it after 24 hours) and never lists them as a library: `GET /v1/stock/search` does not return
them; `output.shots` keeps each shot's licence record (its page, the photographer, the file the copy was made from) —
render the copy (`url`). Where you publish the video or list its
credits, show `output.provided_by` — "Photos and videos provided by Pexels" with the link https://www.pexels.com — and,
where you can, the photographers in `output.photographers` ("Video by Ann on Pexels").

**People in stock footage.** A line about something bad — a scam, failure, loss, debt, fear, illness — is never
illustrated with a recognisable person (hands, objects and places instead): real people must not be shown in a bad
light. In an advert or a sales video send `context: "ad"`: then no stock person and no brand appear at all, so nobody in
the footage seems to endorse the product. The model marks each moment's tone, the plan refuses pictures whose own words
name people for those moments, and the thumbnail check scores any recognisable person there 0.

Never used: NonCommercial, NoDerivatives or ShareAlike material (a ShareAlike clip would make the customer's whole
video ShareAlike), meme GIFs (GIPHY's terms forbid commercial use; Tenor's API is closed) and Coverr (its API is free
only for non-commercial use). Every shot comes back in `output.shots` with its `license`, `attribution`, `credit`,
`author` and `page_url` — keep them with the video. With `attribution: "any"` a CC BY shot is allowed and the planner
puts its credit line on screen while it shows.

**Without a Pexels or Pixabay key** the stock is photographs only (clips need one of them): still real, still free, but a
photo holds still for its 2–3 seconds. `output.summary.stock_video_sources` says what the server has.

## What it costs — and the same video with Veo

The example: the owner's car video with his face never on screen — 12 scenes, 25 Pexels video clips (photos and videos
provided by Pexels), 57.3 s, −15.8 LUFS. A narration-made test (variant B, a 13-second Hebrew script) cost 19 credits:
the voice 5, the plans 3, the render 11.

| Step | Credits | Time |
|---|---|---|
| Upload, two Universal-2 transcripts, sound-only cut, kinetic plan ×2 | 14 | 35 s |
| Gemini 3.1 Flash-Lite picks (watching the video) | 1 | 4 s |
| 4 sound effects | 4 | 2 s (parallel) |
| Music, 59 s | 45 | 12 s |
| **Stock plan** — 12 scenes, 25 Pexels clips: Flash-Lite scenes + 2 thumbnail checks, 25 files copied | 7 | 28 s |
| Render (720p, 57.3 s) | 44 | 2.7 min |
| **Total** | **115** | |

With CC0 photographs only (before the Pexels key) it cost 114 credits — video clips add one credit to the plan.
Covering the same 57 seconds with generated clips would take 15 Veo 3.1 Fast clips of 4 s:
**1800 credits** for the pictures alone, against 7 credits for the stock plan.

## Tune it

`context: "ad"` (an advert: no stock people, no brands) · `shot_seconds` 1.2–6 (a new picture this often) · `kind: "video"` / `"image"` · `attribution: "any"` · `verify: false` ·
`topic` · `moments` (your own scenes: each starts a scene that runs to the next) · everything the kinetic plan takes.

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.
