CLI Quickstart
Install the CLI, authenticate, and create your first podcast from the terminal in a few minutes.
This guide takes you from a clean machine to a finished podcast episode. You'll install the listenhub binary, authenticate (OAuth for interactive use, or an API key for scripts), and run your first generation command — then learn how polling works and how to read the result.
You need Node.js >= 20. The CLI is ESM-only and installs globally as the listenhub binary.
Interactive setup (OAuth)
Use this path when you're working at your own terminal. It signs you in through the browser and acts as your user account.
Install the CLI
npm install -g @marswave/listenhub-cliThis puts the listenhub binary on your PATH. Verify it:
listenhub --version
listenhub --helpLog in
listenhub auth loginThis opens your browser to complete OAuth. After you approve, the CLI stores tokens at ~/.config/listenhub/credentials.json (mode 0600) and prints the account you signed in as. Tokens refresh automatically, so you only do this once per machine.
Confirm your session at any time:
listenhub auth statusCreate your first podcast
Generate a short, single-host episode from a topic:
listenhub podcast create --query "AI agent trends in 2026" --mode quickThe command submits the job, then polls until the episode is ready, showing a spinner with progress. When it finishes it prints the episode ID, title, and status.
A few flags worth knowing on podcast create:
| Flag | Description |
|---|---|
--query <text> | The topic or prompt for the episode. |
--source-url <url> | A reference URL to ground the episode. Repeatable. |
--source-text <text> | Reference text to ground the episode. Repeatable. |
--mode <mode> | quick, deep, or debate. Default quick. |
--lang <lang> | en, zh, or ja. Auto-detected from your query if omitted. |
--speaker <name> | Speaker by name. Repeatable. One speaker produces a solo episode; two or more make a multi-voice episode. |
--speaker-id <id> | Speaker by inner ID. Repeatable. Use instead of --speaker when you already know the ID. |
If you omit speakers, the CLI picks defaults for the detected language. To pick voices deliberately, list speakers first (the openapi namespace exposes a queryable list — see the API-key path below) and pass --speaker or --speaker-id.
Read the result
By default the command waits for generation to finish, so the final output already reflects a completed episode:
✓ Podcast created
ID: ep_xxx
Title: AI agent trends in 2026
Status: successList your recent episodes any time:
listenhub podcast listHow polling works
Generation is asynchronous. Every creation command submits a job, gets back an ID, then polls the API until the job reaches a terminal state.
- Interval. The CLI checks status every 10 seconds.
- Timeout.
--timeout <seconds>caps how long it waits. The default forpodcast createis300(5 minutes). When the timeout is hit before the job finishes, the command exits with code3— the job keeps running server-side, and you can fetch it later by ID. - Outcome. On success the command prints the finished episode. On a server-side failure it prints the failure and exits non-zero.
To skip polling entirely, pass --no-wait. The command returns the ID immediately and exits 0:
listenhub podcast create --query "AI agent trends in 2026" --no-wait
# ✓ Podcast submitted: ep_xxxFor scripts and CI, combine --no-wait with --json (-j). --json prints machine-readable output to stdout (errors stay on stderr), so you can pipe straight into jq:
ID=$(listenhub podcast create --query "Weekly recap" --no-wait -j | jq -r '.episodeId')Then poll on your own schedule, or fetch the episode once your own job runner reports it ready.
Scripting setup (API key)
On a server or in CI, use an API key instead of OAuth. API-key commands live under the listenhub openapi namespace and act as the key's owner.
Create an API key
Create a key at listenhub.ai/settings/api-keys. Keys start with lh_sk_.
Make the key available
Two options. For CI and ephemeral environments, set the environment variable — the CLI reads it first:
export LISTENHUB_API_KEY="lh_sk_..."For a persistent local setup, store it on disk instead. The command prompts for the key and writes it to ~/.config/listenhub/openapi.json (mode 0600):
listenhub openapi config set-keyCheck what's configured (and which source is in effect) with:
listenhub openapi config showPick a speaker
Unlike the OAuth path, openapi podcast create requires at least one --speaker-id. List the available voices and copy an ID:
listenhub openapi speakers list --language enThis prints a table of Name, ID, Gender, and Language. The ID column is what you pass to --speaker-id.
Create a podcast with the API key
listenhub openapi podcast create \
--query "AI agent trends in 2026" \
--speaker-id <speaker-id> \
--mode quickLike the OAuth command, it submits the job and polls to completion, printing the episode details when done. The same --no-wait, --timeout <seconds> (default 300), and --json flags apply. Pass --speaker-id more than once for a multi-voice episode, and add --source-url / --source-text to ground the content.
Fetch an episode by ID later:
listenhub openapi podcast get <episode-id>Exit codes
Scripts can branch on the exit code:
| Code | Meaning |
|---|---|
0 | Success |
1 | Error (validation, API error, network failure) |
2 | Authentication required or invalid — run listenhub auth login again, or check your API key |
3 | Timeout — polling exceeded --timeout before the task finished |
Estimating credits
Generation consumes credits. Before creating, check the cost with the relevant estimate command for the product you're using — for example listenhub openapi video estimate or listenhub video estimate — and check your remaining balance with listenhub openapi subscription. Never assume a fixed cost — query it.
Next steps
CLI overview
The two auth modes, command namespaces, and global flags at a glance.
Authentication
OAuth login vs. API key, where credentials live, and switching between them.
OpenAPI commands
Every listenhub openapi command for scripts and CI, keyed off your API key.
JavaScript SDK
The library the CLI wraps — for when you want to call ListenHub from code.