Developer tools · command line & API

TubeTube CLI: make AI videos from your terminal

Updated · CLI v1.0.0 · API v1

On this pageInstallationAuthenticationQuickstartGlobal flagsCommandscreatelistgetwatchdownloadassetsdeletestyles, engines, optionswhoami, creditsShell completionRecipesREST APIError codesEnvironmentFAQ
The tubetube command line tool creates videos, follows their generation and downloads the finished files without leaving your terminal. It runs on Node.js 18.17+, has no dependencies, and speaks the same public REST API you can call from any language.

Installation

Nothing to install: npx fetches the latest version each time it runs. Install it globally if you use it daily.

npx tubetube --help

# or, to keep it around
npm install -g tubetube
tubetube version

Node.js 18.17 or newer is the only requirement, on macOS, Linux or Windows. The package has zero dependencies, so nothing else lands in your node_modules.

Authentication

Create a key on your Account page, then log in once.

tubetube login                    # asks for the key and verifies it
tubetube login --key tt_live_…    # non-interactive
tubetube whoami                   # account, plan, credits
tubetube logout                   # forget the stored key

The key is stored in ~/.tubetube/config.json with owner-only permissions. It is shown in full only once, at creation: the server keeps a SHA-256 hash of it, never the key itself. Revoking a key on the Account page takes effect immediately.

In CI, set TUBETUBE_API_KEY as a secret instead of running login. It takes precedence over the stored key and nothing is written to the disk of the runner.

A key can create, read, download and delete videos on your account. It can never use operator-only settings such as automatic publishing to Google Drive, even on an admin account.

Quickstart

npx tubetube login
npx tubetube styles                       # pick a look
npx tubetube create --title "Counting song" \
    --style "Pixar-style 3D" \
    --lyrics-file song.txt \
    --scene-duration 5 \
    --dry-run                             # what would it cost?

npx tubetube create --title "Counting song" \
    --style "Pixar-style 3D" \
    --lyrics-file song.txt \
    --scene-duration 5 \
    --wait --download                     # launch, follow, save the mp4

Global flags

FlagMeaning
-o, --output <fmt>text (default) or json. Accepted by every command.
--jsonShorthand for -o json.
-h, --helpHelp for the command. tubetube help <command> works too.

Every command exits with a non-zero status on failure, including watch when the generation itself fails, so a script stops on its own. Unknown options are rejected rather than ignored: a typo cannot silently change your settings and waste credits.

Commands

create

Builds the parameters, asks the server for a price, then launches. Credits are reserved at launch and whatever is not produced is refunded when the job ends.

# Price it, launch nothing
tubetube create --title "My song" --style "Pixar-style 3D" \
    --lyrics-file song.txt --dry-run

# Launch and follow until the file is on disk
tubetube create --title "My song" --style "Pixar-style 3D" \
    --lyrics-file song.txt --wait --download

# Same recipe as a previous video, new words
tubetube create --from a1b2c3d4 --lyrics-file new-song.txt --wait

# Text from stdin
cat script.txt | tubetube create --type narration --style "Watercolor storybook"

The text comes from --lyrics, --lyrics-file, stdin, or the video referenced by --from. The visual style is required: pass --style with a preset name or --style-text with your own prompt.

OptionMeaning
--title <text>Title of the video. Defaults to the first non-empty line of the text.
--type <kind>song (default), narration or dialogue.
--format <ratio>16:9 (default) or 9:16 for shorts.
--lyrics <text>Lyrics or script, inline.
--lyrics-file <file>Read the text from a file. You can also pipe it on stdin.
--style <name>Visual style by name, fuzzy-matched. See tubetube styles.
--style-text <prompt>Free-form visual style instead of a preset.
--engine <id>Video engine. See tubetube engines.
--scene-duration <s>Seconds per scene. 5 keeps the visuals on the beat; 10 makes them lag behind fast lyrics. Allowed values depend on the engine.
--duration <s>Target length of the finished video, in seconds.
--audio-source <src>suno, elevenlabs, elevenlabs_tts, upload or upload_cover.
--music-style <text>Musical direction for the generated song.
--voice <id>ElevenLabs voice id for narration.
--image-model <id>Image model. See tubetube options.
--upscale <mode>none, 2k or 4k.
--motion <style>Motion style, e.g. natural, stop_motion, anime.
--language <code>Spoken language for dialogue videos.
--scene-instructions <t>Manual scene cutting instructions.
--no-syncDisable word-by-word visual syncing.
--bg-soundAdd a background ambience track.
--from <video-id>Reuse every setting of an existing video.
--params-file <file>Full params JSON, for advanced use.
--tags <a,b,c>Comma-separated tags.
--description <text>Video description.
--dry-runPrint the credit cost and stop.
--waitFollow progress until the video is ready.
--downloadWith --wait, download the result when it finishes.
--output-dir <dir>With --download, where to save.
Scene duration matters more than anything else for timing. The picture can only change when a clip ends, so 10-second scenes make the visuals lag behind fast lyrics. Use 5 seconds for songs.

list

Your videos, newest first. Ids are shortened to their first 8 characters.

tubetube list
tubetube list --status processing
tubetube list --limit 50 -o json
tubetube list --cursor 2026-08-30T20:36:23Z   # next page
OptionMeaning
--status <s>queued, processing, completed, failed or canceled.
--limit <n>Rows per page, up to 100. Default 20.
--cursor <iso>Pagination cursor printed at the end of the previous page.

get

Everything about one video: type, style, engine, credits, every pipeline step with its state, and a summary of the files produced.

tubetube get a1b2c3d4
tubetube get a1b2c3d4 -o json | jq .steps

watch

Polls until the video reaches a final state, drawing a progress bar with the step currently running. In -o json mode it prints one JSON object per poll, which is what you want in a log.

tubetube watch a1b2c3d4
tubetube watch a1b2c3d4 --interval 15   # seconds between polls, minimum 2

download

Downloads the finished files. The main video is renamed after the video title, so several downloads can live in the same folder.

tubetube download a1b2c3d4                            # the finished video
tubetube download a1b2c3d4 --all --output-dir ./out   # every scene, image and audio file
tubetube download a1b2c3d4 --asset archive            # the zip of all assets
tubetube download a1b2c3d4 --url-only                 # print signed URLs instead
OptionMeaning
--asset <what>video (default), archive or all.
--allSame as --asset all.
--output-dir <dir>Where to save. Created if needed. Default: current folder.
--url-onlyPrint signed URLs, valid one hour, instead of downloading.

Downloads made without a subscription carry a small tubetube.io mark. Subscribing later makes every video you have already made downloadable clean.

assets

Lists every file of a video with its kind, scene number, size and duration.

tubetube assets a1b2c3d4
tubetube assets a1b2c3d4 -o json | jq '[.assets[] | select(.kind=="scene_video")] | length'

delete

Permanent: the files are removed from storage and the record is dropped. Refused while a job is still running.

tubetube delete a1b2c3d4          # asks for confirmation
tubetube delete a1b2c3d4 --yes    # no prompt, for scripts

styles, engines, options

The accepted values, straight from the server, so you never have to guess an identifier like veo31fast720.

tubetube styles              # featured and custom styles
tubetube styles --all        # the full catalogue
tubetube engines             # engines and the scene durations each one allows
tubetube options -o json     # everything, machine-readable

whoami, credits

tubetube whoami     # email, plan, balance, watermark status, key source
tubetube credits    # just the number, handy in a shell prompt

Shell completion

# zsh — add to ~/.zshrc
source <(tubetube completion zsh)

# bash — add to ~/.bashrc
source <(tubetube completion bash)

# fish
tubetube completion fish > ~/.config/fish/completions/tubetube.fish

Recipes

One video a day, from a cron job

#!/usr/bin/env bash
set -euo pipefail
export TUBETUBE_API_KEY="$(cat ~/.secrets/tubetube)"

id=$(tubetube create --title "Daily story $(date +%F)" \
      --type narration --style "Watercolor storybook" \
      --lyrics-file "$HOME/stories/$(date +%F).txt" \
      -o json | jq -r .video.id)

tubetube watch "$id"                        # exits non-zero if it fails
tubetube download "$id" --output-dir ~/out

Batch: same recipe, many texts

for f in lyrics/*.txt; do
  tubetube create --from a1b2c3d4 --lyrics-file "$f" \
      --title "$(basename "$f" .txt)" -o json | jq -r .video.id
done > ids.txt

xargs -a ids.txt -I{} tubetube watch {}

Check the cost before spending

tubetube create --title x --style "Pixar-style 3D" \
    --lyrics-file song.txt --dry-run -o json | jq '{credits, scenes, balance: .quote.balance}'

REST API

The CLI is a thin client: every command is one HTTP call. Authenticate with Authorization: Bearer tt_live_…. Responses are JSON; errors always look like { "error": { "code": "…", "message": "…" } }.

EndpointPurpose
GET /api/v1/meAccount, plan, credit balance, whether downloads are watermark-free.
GET /api/v1/videosList videos. Query: status, limit (max 100), cursor.
POST /api/v1/videosCreate and launch. Body: title, description, tags, params.
GET /api/v1/videos/{id}Status, progress, steps, credits, files.
DELETE /api/v1/videos/{id}Delete permanently. 409 while a job is running.
GET /api/v1/videos/{id}/downloadSigned URLs. Query: asset=video|archive|all.
POST /api/v1/quotePrice a video without launching it.
GET /api/v1/optionsStyles, engines with their scene durations, image models.
# List videos
curl -s https://www.tubetube.io/api/v1/videos \
  -H "Authorization: Bearer $TUBETUBE_API_KEY"

# Price a video without launching it
curl -s https://www.tubetube.io/api/v1/quote \
  -H "Authorization: Bearer $TUBETUBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"params":{"contentType":"song","format":"9:16",
       "lyrics":"Twinkle twinkle little star, how I wonder what you are",
       "imageStyle":"3D CGI in the style of Pixar, rounded expressive characters",
       "audioSource":"suno"}}'

# Create and launch
curl -s -X POST https://www.tubetube.io/api/v1/videos \
  -H "Authorization: Bearer $TUBETUBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"My song","params":{ … }}'

GET /api/v1/options returns the full prompt of every style, which is what you put in params.imageStyle. params accepts the same fields as the web wizard; anything you omit takes its default server-side.

Error codes

CodeMeaning
missing_api_keyNo Authorization header. 401.
invalid_api_keyUnknown, malformed or revoked key. 401.
invalid_jsonThe body is not valid JSON. 400.
invalid_bodyParameters rejected by validation; details lists the fields. 400.
invalid_reference_imagesA reference image path does not belong to your account. 400.
insufficient_creditsNot enough credits; needed and balance are included. 402.
insufficient_scopeThe key does not carry the required right. 403.
not_foundNo video with this id on your account. 404.
asset_not_readyThe requested file does not exist yet. 404.
job_runningThe video is still generating and cannot be deleted. 409.
pricing_unavailableThe pricing table could not be read; retry. 503.

The CLI turns these into one-line messages and a non-zero exit status. With -o json it prints the error object instead, so a script can branch on .error.code.

Environment

VariableEffect
TUBETUBE_API_KEYUse this key instead of the stored one. Nothing is written to disk.
TUBETUBE_API_URLPoint the CLI at another instance. Defaults to https://www.tubetube.io.
NO_COLORDisable colours. Colours are also off when the output is piped.

Frequently asked questions

Do I need to install anything?

No. npx tubetube <command> runs the latest version straight away, and it has no dependencies. Node.js 18.17 or newer is the only requirement. npm install -g tubetube keeps it around if you prefer.

How do I authenticate?

Create an API key on your Account page, then run tubetube login and paste it. The key is stored in ~/.tubetube/config.json, readable by you only. In CI, set the TUBETUBE_API_KEY environment variable instead and nothing is written to disk.

Does the CLI cost extra?

No. It spends the same credits as the web app, at the same rate. tubetube create --dry-run prints the exact cost before you launch anything, and whatever a job does not produce is refunded to your balance.

Can I use it in a CI pipeline?

Yes. Every command accepts -o json and exits non-zero on failure, including when a generation fails. Set TUBETUBE_API_KEY as a secret, then chain tubetube create -o json, tubetube watch and tubetube download.

Are downloads watermarked?

On a free account, yes: downloads carry a small tubetube.io mark, exactly as in the web app. Any paid plan exports clean files, and subscribing later makes every video you have already made downloadable clean again.

Can an API key do everything my account can?

Almost. A key can create, read, download and delete videos. It can never use the operator-only settings such as automatic publishing to Google Drive, even on an admin account, so a leaked key cannot publish anything in your name.

What happens if I lose a key?

Revoke it on the Account page; it stops working immediately. Keys are stored as a SHA-256 hash, so nobody, including us, can read an existing key. Create a new one and run tubetube login again.

Try it in one line

Sign up, create a key, and your first video is a single command away. New accounts get 1,000 credits, valid 7 days, no card required.

npx tubetube login && npx tubetube styles
Create a free account