Browse the docs
Developers / Docs / Templates
Create Roblox rant video
Makes a Roblox rant video draft: a narration over Roblox (or other) gameplay with bold word-by-word captions, the pauses cut out and AI emojis on the punchy lines. Give one of script, prompt (a script is written for durationSeconds, free) or voiceoverFileId (your own narration, transcribed for free). A generated voice spends about 1 voiceover and 1 caption minute per minute of narration; silence removal and AI emojis are free. By default it makes a draft: the job output has projectId, stills (frames to check the look), previewUrl (plays it in the browser) and editorUrl. Restyle it with update_video (free), then render_video. "render": true goes straight to an MP4 (spends export minutes). Run dryRun: true (or estimate_cost) first and confirm the cost. Takes about a minute: wait with get_job (waitSeconds). At most 3 videos are made at once per account.
Paste it into any AI assistant. The shortcuts open with the prompt typed in; nothing is sent until you press enter.
At a glance
- REST
POST https://api.clippie.ai/v1/videos/roblox-rant
- MCP tool
create_roblox_video
- Scope
create
- Cost
- Spends credits or minutes, at the same prices as the app. Send
"dryRun": true(or call estimate_cost) first to see the exact cost without spending anything.
- Spends credits or minutes, at the same prices as the app. Send
- Limit bucket
voiceover(see Rate limits)
Parameters
prompt- In:
- body
- Type:
- string
- Required:
- No
- Description:
- What the rant is about; a script is written from it (free) to fill durationSeconds. Give one of prompt, script or voiceoverFileId. 3-2000 chars.
script- In:
- body
- Type:
- string
- Required:
- No
- Description:
- The exact narration to use. Punctuation is not read out (the Roblox voice reads it as one rant). 3-6000 chars.
voiceoverFileId- In:
- body
- Type:
- string
- Required:
- No
- Description:
- file_… id of your own narration audio (upload_file). It is transcribed for the captions for free; no voice is generated. Up to 5 minutes. Up to 80 chars.
durationSeconds- In:
- body
- Type:
- integer
- Required:
- No
- Description:
- Length of the narration in seconds (30-300, default 60) when the script is written from prompt. 30-300.
theme- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Subject direction for a script written from prompt. One of
any,historical,scientific,geography,politics,nature,religion,technology,psychology,mystery,space,mythology,war.
tone- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Voice and pacing for a script written from prompt. One of
cinematic,suspenseful,educational,dark,inspirational,humorous,dramatic,casual,horror,scary,thriller,creepy.
title- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Project and file name. Defaults to the start of the prompt or script. 1-120 chars.
voiceId- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Narration voice id from list_voices (Clippie voices or your own cloned ones). Defaults to your brand voice. 1-64 chars.
language- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Narration and caption language code from list_languages (e.g. "en", "es"). Default: detected. Up to 10 chars.
removeSilence- In:
- body
- Type:
- boolean
- Required:
- No
- Description:
- Default true: cut the pauses out of the narration (free), as the editor's "Remove silences" does.
aiEmojis- In:
- body
- Type:
- boolean
- Required:
- No
- Description:
- Default true: put emojis on the punchy caption lines with AI (free), as "Add Emojis with AI" does.
backgroundVideoId- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Background clip id from list_background_videos. Default: the editor's Roblox clip. Up to 80 chars.
backgroundGenre- In:
- body
- Type:
- string
- Required:
- No
- Description:
- A list_background_videos category (e.g. "Roblox", "Minecraft"): picks a clip from it. Give this or backgroundVideoId. Up to 60 chars.
musicId- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Background music id from list_music, or "none". Defaults to your brand track (none without one). Up to 80 chars.
musicVolume- In:
- body
- Type:
- number
- Required:
- No
- Description:
- Music volume, 0-100. Default 1, the editor's (quiet under the narration). 0-100.
captionStyleId- In:
- body
- Type:
- integer
- Required:
- No
- Description:
- Caption style id from list_caption_styles. One-word styles are not offered for Roblox videos. Defaults to your brand caption style, then 2.
captionPosition- In:
- body
- Type:
- number
- Required:
- No
- Description:
- Vertical position of the captions, 0 (top) to 100 (bottom). Default 33. 0-100.
captionSize- In:
- body
- Type:
- number
- Required:
- No
- Description:
- Caption size, 0-100 (50 is the default). 0-100.
textStyle- In:
- body
- Type:
- object
- Required:
- No
- Description:
- Colour, case, outline and shadow over the caption style.
playbackRate- In:
- body
- Type:
- number
- Required:
- No
- Description:
- Narration speed, 1-2 (default 1). Shortens the video. 1-2.
pitch- In:
- body
- Type:
- number
- Required:
- No
- Description:
- Voice pitch, 0.1-2 (default 1). Only the rendered MP4 has it: the stills and the preview page play the normal pitch. 0.1-2.
ratio- In:
- body
- Type:
- string
- Required:
- No
- Description:
- Frame shape. Roblox rants are 9:16, the only shape the editor makes. One of
9:16.
render- In:
- body
- Type:
- boolean
- Required:
- No
- Description:
- Default false: make an editable draft and return stills and previewUrl. true also renders the MP4 (spends export minutes).
dryRun- In:
- body
- Type:
- boolean
- Required:
- No
- Description:
- Check the request and return { estimate } (credits and minutes) without spending anything.
webhookUrl- In:
- body
- Type:
- string (URL)
- Required:
- No
- Description:
- https URL that receives job.completed / job.failed, signed with your webhook secret. Up to 2048 chars.
Idempotency-Key- In:
- header
- Type:
- string
- Required:
- No
- Description:
- Retry-safe key: a retry with the same key and body within 24 hours returns the first job instead of starting (and charging) again. The same key with a different body is a 409. MCP clients pass it as the idempotencyKey argument. 1-255 chars. MCP:
idempotencyKey.
Example
# 1. Dry run: the exact cost, nothing is spent.
curl https://api.clippie.ai/v1/videos/roblox-rant \
-H "Authorization: Bearer $CLIPPIE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dryRun": true
}'
# => { "dryRun": true, "estimate": { "credits": ..., "minutes": { ... }, "wouldSucceed": true } }
# 2. The real call. Keep the key and send the same one if you retry, so it is never charged twice.
KEY=$(uuidgen)
curl https://api.clippie.ai/v1/videos/roblox-rant \
-H "Authorization: Bearer $CLIPPIE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d '{}'
# => 202 { "job": { "id": "job_...", "status": "queued", ... } }import { randomUUID } from 'node:crypto';
const auth = { Authorization: `Bearer ${process.env.CLIPPIE_API_KEY}` };
const input = {};
async function call(body, headers = {}) {
const res = await fetch('https://api.clippie.ai/v1/videos/roblox-rant', {
method: 'POST',
headers: { ...auth, 'Content-Type': 'application/json', ...headers },
body: JSON.stringify(body),
});
const json = await res.json();
if (!res.ok) throw new Error(`${json.error.type}: ${json.error.message}`);
return json;
}
// 1. Dry run: the exact cost, nothing is spent. Confirm it before going on.
const { estimate } = await call({ ...input, dryRun: true });
console.log(estimate); // { credits, minutes, wouldSucceed, reason }
// 2. Create. Keep the key and reuse it on retries, so a retry never charges twice.
let { job } = await call(input, { 'Idempotency-Key': randomUUID() });
// 3. Wait. Each call holds for up to 30 seconds until the job changes.
while (!['completed', 'failed', 'canceled'].includes(job.status)) {
const res = await fetch(`https://api.clippie.ai/v1/jobs/${job.id}?wait=30`, { headers: auth });
({ job } = await res.json());
}
console.log(job.status, job.output);Response
202 { job }: the job, straight away. Wait for it with Get job (?wait=30) or a webhookUrl; see Jobs and waiting. With "dryRun": true the answer is 200 { dryRun: true, estimate } and nothing is started.
{
"job": {
"id": "job_abc123",
"object": "job",
"kind": "create_roblox_video",
"status": "queued",
"step": null,
"progress": null,
"input": {
"prompt": "The lost library of Alexandria"
},
"output": null,
"cost": {
"credits": 0,
"minutes": {
"voiceover": 1,
"captions": 1,
"export": 1
}
},
"error": null,
"source": "api",
"webhookUrl": null,
"createdAt": "2026-10-24T12:00:00.000Z",
"startedAt": null,
"completedAt": null
}
}{
"dryRun": true,
"estimate": {
"credits": 0,
"minutes": {
"voiceover": 0,
"captions": 0,
"export": 0
},
"wouldSucceed": true
}
}From an MCP client
Your AI calls create_roblox_video with the same fields as JSON arguments, plus idempotencyKey instead of the header. See MCP server to connect one.
{
"name": "create_roblox_video",
"arguments": {
"idempotencyKey": "a-unique-key-per-thing-you-make"
}
}