Skip to main content

sonilo-cli

Command-line interface for the Sonilo API — generate music and sound effects from text or video.

Install

pip install sonilo-cli

Signing in

Run this once per machine — there is no key to create, paste, or export:

sonilo login

It prints a one-time code and opens your browser to platform.sonilo.com. Sign in, confirm the code matches what the terminal printed, and approve; the CLI is waiting on that page and continues by itself. Every command works from then on.

Approving mints an ordinary Sonilo API key on your account, named cli: <hostname> and valid for 90 days, stored in ~/.config/sonilo/credentials.json ($XDG_CONFIG_HOME/sonilo/ when that is set), owner-readable only. It is visible and revocable at the dashboard like any other key.

sonilo whoami    # which account, key prefix, expiry, and which source is active
sonilo logout    # revoke the key server-side, then forget it locally

logout revokes before forgetting, so a machine that loses the file never leaves a live key behind. If the revoke cannot reach the API the credential is deliberately kept and you are pointed at the dashboard, rather than being left holding a key nothing can revoke.

Signing in again while already signed in reports the existing session; use --force to replace it (that mints a fresh key and revokes the one it replaces). When a credential has expired you do not need the flag — sonilo login treats an expired sign-in as no sign-in. On a machine with no browser, add --no-browser and approve the printed URL from another device.

The credential file is shared with the JS CLI (npm install -g sonilo-cli) and read by sonilo-mcp 0.16.0+, so one sign-in covers all three — an MCP host config then needs no env block at all.

Auth with an API key

Signing in is optional. A key from the dashboard works exactly as it always has, which is what you want for CI, containers, and anything non-interactive — there is no browser there to approve with, and a 90-day expiry is not something a pipeline should depend on:

export SONILO_API_KEY=sk-...

or pass --api-key sk-... on any command.

Credentials resolve most-explicit-first: --api-key, then SONILO_API_KEY, then the stored sign-in. That order is a guarantee, not an accident — an exported SONILO_API_KEY keeps winning after you upgrade, so adding a sonilo login on the same machine cannot quietly move your calls to another account.

Set SONILO_API_URL (or pass --api-base to login) to point at another environment. Credentials are stored per host, so a staging sign-in and a production sign-in coexist without overwriting each other.

Commands

sonilo login                       # sign in with your browser, no key needed
sonilo whoami                      # show the active account and credential source
sonilo logout                      # revoke the stored key and forget it
sonilo account                     # plan limits and available services
sonilo usage --days 7              # usage summary
sonilo text-to-music --prompt "warm lo-fi piano, rain" --duration 30
sonilo video-to-music --video clip.mp4 --prompt "tense synths" --format wav
sonilo text-to-sfx --prompt "glass shattering on concrete" --duration 3
sonilo video-to-sfx --video clip.mp4 --output whoosh.wav
sonilo video-to-sfx --video clip.mp4 --segments @segments.json
sonilo video-to-sound --video clip.mp4 \
    --music-prompt "uplifting orchestral score" --sfx-prompt "match the on-screen action"
sonilo video-to-video-music --video clip.mp4 --prompt "tense synths" --output scored.mp4
sonilo video-to-video-sfx --video clip.mp4 --segments @segments.json --output scored.mp4
sonilo video-to-video-sound --video clip.mp4 --music-prompt "tense synths"
sonilo audio-ducking --voice interview.mp4 --music-url https://example.com/bed.wav
# ducks the existing music bed under the voice; a video voice comes back
# as a new .mp4 with the ducked mix muxed in
sonilo video-analysis --video clip.mp4 --variants 2
# prints a creative brief as JSON; generates nothing
sonilo proofread --video clip.mp4 --languages ja,zh_cn --output scripts/clip.srt
# writes scripts/clip.<lang>.srt, including the detected source language
sonilo dubbing --video-url https://example.com/clip.mp4 --languages es,fr --output dubbed.mp4
# writes dubbed.es.mp4 and dubbed.fr.mp4
sonilo tasks get <task-id>
sonilo tasks wait <task-id> --poll-interval 2 --timeout 600

Notes

  • text-to-music / video-to-music stream a short .m4a by default. --format wav, --preserve-speech, --variants above 1, --stems, and the legacy alias --isolate-vocals each switch to the async submit-and-poll path.
  • text-to-sfx / video-to-sfx are always async; --format accepts wav|mp3|aac|flac.
  • Output defaults to ./output.<ext>; override with --output.

Segments

--segments scores a timeline instead of one whole-clip prompt. It takes a JSON array, in one of three forms — inline, from a file, or from stdin:

sonilo text-to-music --prompt "warm lo-fi piano" --duration 30 \
    --segments '[{"start":0,"label":"intro","prompt":"airy pads"}]'
sonilo video-to-sfx --video clip.mp4 --segments @segments.json
jq -c '.cues' storyboard.json | sonilo video-to-sfx --video clip.mp4 --segments @-

A value starting with @ names a source to read the JSON from, and @- reads standard input — the same convention as curl, gh and aws. Anything else is parsed as JSON directly.

The two segment shapes are not interchangeable:

Shape Commands Fields
Music text-to-music, video-to-music {start, prompt, label?}
SFX video-to-sfx, video-to-video-sfx, video-to-sound, video-to-video-sound {start, end, prompt}
  • start / end are seconds from the start of the track or clip.
  • Passing one shape to a command that takes the other is rejected before any request is made, with a message naming the shape that command expects.
  • Only the shape is checked locally. Timing rules — the first segment starting at 0, minimum spacing between segments, the label vocabulary, how many segments are allowed — are enforced by the API, which answers with a 422 describing what it rejected.
  • Keys the CLI does not recognise are forwarded as-is, so a newly added API field works without upgrading the CLI.
  • text-to-sfx takes no segments (its output is a single effect, not a timeline).
  • video-to-video-music takes no segments either — the API scores the whole clip in one pass.

Variants

--variants N (1-10, default 1) generates that many distinct variants in one request instead of one, on text-to-music, video-to-music, video-to-video-music, video-to-sound, and video-to-video-sound. Cost scales linearly — --variants 3 costs three times a single-variant request — and values above 1 are never covered by the free trial.

sonilo text-to-music --prompt "warm lo-fi piano" --duration 30 --variants 3 --output take.m4a
# writes take.0.m4a, take.1.m4a, take.2.m4a
  • --variants above 1 forces the async submit-and-poll path (see Notes above).
  • With --variants unset (or 1), a command writes the single --output file exactly as before this flag existed. Above 1, it instead writes one file per variant, with the variant index spliced before the extension: take.m4a becomes take.0.m4a, take.1.m4a, etc. — the same naming --stem and dubbing's per-language output already use.
  • On video-to-sound / video-to-video-sound, --stem is applied per variant too, e.g. take.0.music.m4a.

Prompt influence

--prompt-influence (0-1, API default 0.5) sets how strongly the generated music follows the prompt, on video-to-music and video-to-video-music only. Lower values let the video lead; higher values follow the prompt more literally. It is free of charge, and unlike --format wav it does not force the async path — it works on the streaming default too. Left unset, the field is not sent at all and the API's own 0.5 default applies; --prompt-influence 0 is a real value ("let the video lead entirely") and is sent. Out-of-range values earn a 422 from the API.

sonilo video-to-music --video clip.mp4 --prompt "tense synths" --prompt-influence 0.8

Music stems

--stems on text-to-music and video-to-music also splits the generated music into four stems — drums, bass, vocals, other — saved next to the main output with the stem name spliced before the extension (take.m4atake.drums.m4a, and per variant with --variants above 1: take.0.drums.m4a). It is free of charge, and forces the async path. On video-to-music it splits the generated music, never the video's own audio.

sonilo text-to-music --prompt "warm lo-fi piano" --duration 60 --stems --output take.m4a
# writes take.m4a, take.drums.m4a, take.bass.m4a, take.vocals.m4a, take.other.m4a
  • Separation runs after generation and typically adds 2-6 minutes to the wait; the CLI waits up to 2400 seconds on these runs (covering the separation service's own 30-minute ceiling, the way dubbing's --timeout covers its backend's). If the wait still times out, the task keeps running server-side — resume it with sonilo tasks wait <task-id>.
  • Separation can also come up short without failing the run: streams that did not separate are reported on stderr (the API's stems_error), while the stems that did come back are still saved — a partial result is not an error exit, and the main output is always written.
  • Not the same flag as --stem on the sound commands, which saves layers those endpoints already return; --stems requests a separation the API would not otherwise run.

Scored video

video-to-video-music and video-to-video-sfx are the video-out counterparts of video-to-music and video-to-sfx: same generation, but what comes back is the source picture with the new audio already muxed in, so there is nothing to line up afterwards. Both are async-only and write a single file (default output.mp4):

sonilo video-to-video-music --video clip.mp4 --prompt "tense synths" --output scored.mp4
sonilo video-to-video-sfx --video clip.mp4 \
    --segments '[{"start":0,"end":5,"prompt":"footsteps on gravel"}]' --output scored.mp4
  • --prompt is optional on both; without it the model scores from the picture alone.
  • video-to-video-music also takes --preserve-speech, which keeps source speech in the mix; omitting it leaves the server default untouched. --isolate-vocals is a legacy alias for the same flag — the API ORs the two together, and this endpoint returns one muxed video with no separate vocals stem.
  • video-to-video-sfx takes --segments in the SFX shape {start, end, prompt} — see Segments.
  • Neither command exposes --format: the output is a video, not an audio file.
  • For music and effects in one call, use video-to-video-sound below.
  • video-to-video-music also takes --variants — see Variants above. video-to-video-sfx does not.
  • video-to-video-music also takes --prompt-influence — see Prompt influence above. video-to-video-sfx does not.

Combined soundtracks

video-to-sound and video-to-video-sound score a clip with a music bed and sound effects in one call (one charge, instead of chaining two requests). Both are async-only and take the same options — they differ only in what comes back: video-to-sound writes the mixed audio (default output.wav), video-to-video-sound writes the source video with that audio muxed in (default output.mp4).

sonilo video-to-sound --video clip.mp4 \
    --music-prompt "uplifting orchestral score" \
    --sfx-prompt "match the on-screen action" \
    --output soundtrack.wav --stem music --stem sfx
  • --music-prompt / --sfx-prompt steer the two layers separately; both are optional.
  • --segments places individual effects on the timeline, in the SFX shape {start, end, prompt} — see Segments.
  • --preserve-speech keeps speech from the source video in the mix.
  • Ducking is off by default. Pass --ducking to bring the source video's own speech into the mix with the generated bed dipped under it — without it the result is the generated music and effects alone. Omitting both flags leaves the server default untouched; --no-ducking still works and now just states that default explicitly.
  • --stem is repeatable (music, music_processed, sfx) and saves the individual layers next to the combined output, so you can re-balance the mix yourself. With --output soundtrack.wav, the music stem lands at soundtrack.music.m4a. music_processed exists only when --preserve-speech or ducking altered the music bed.
  • Both also take --variants — see Variants above.

Audio ducking

audio-ducking mixes an existing music bed under an existing voice track — nothing is generated, so reach for it when the music is fixed or external. (When the music is being generated for the same clip anyway, video-to-sound or video-to-music duck internally as part of that one call instead.)

sonilo audio-ducking --voice interview.mp4 --music-url https://example.com/bed.wav
  • Exactly one of --voice / --voice-url and one of --music / --music-url; a local file and a URL mix freely across the two inputs.
  • The voice may be audio or video: a video's own audio track becomes the voice, and the ducked mix is muxed back into a new video, so the result is a .mp4 instead of a .wav. The default --output name follows what came back (output.wav or output.mp4).
  • The music must be audio (wav, mp3, m4a, aac, ogg, flac). The API does not detect a video there, so the CLI rejects a local video file up front rather than let it be mishandled silently.
  • Each input is capped at 360 seconds server-side.

Video analysis

video-analysis analyzes a video and prints a creative brief for scoring it. It is the one command that produces no media file — nothing is generated:

sonilo video-analysis --video clip.mp4 --prompt "focus on the chase" --variants 2
  • The brief goes to stdout as JSON so it can be piped into another tool: segments (a time-aligned section plan) and variations (one ready-to-use generation prompt each). Pass --output brief.json to write it to a file instead.

  • --variants is 1-5 (default 1) and is billed per brief.

  • --mode is both (default), music or sfx. both adds a sound-design brief to the JSON: sfx_segments (shot-sized sections) and sfx_prompt (one string). music reproduces the previous output shape. Same price for all three.

  • Source videos may be at most 480 seconds long, and billing has a 10-second floor.

  • Feed a variation's prompt straight into the next command:

    sonilo video-analysis --video clip.mp4 --output brief.json
    sonilo video-to-music --video clip.mp4 --prompt "$(jq -r '.variations[0].prompt' brief.json)"
    

Proofread

proofread transcribes a video and translates the transcript into editable .srt files — one per language, plus the source-language transcript. The video must have an audio track. Nothing is dubbed: this is the step before dubbing, so the wording can be corrected before any voice is rendered.

sonilo proofread --video clip.mp4 --languages ja,zh_cn --output scripts/clip.srt
# writes scripts/clip.en.srt, scripts/clip.ja.srt, scripts/clip.zh_cn.srt
  • --languages is comma-separated and takes the same codes as dubbing (see Dubbing below for the list), so a proofread script can go straight into a dub. Omit it for the source-language transcript alone.

  • --source-language tells transcription which language to expect, which helps on short, noisy or mixed-language audio. Omit it to have the language detected; either way the detected code is printed and names the source-language file.

  • --output is a filename template, not a single destination, exactly as it is for dubbing: one .srt is written per language with the code inserted before the extension, so --output scripts/clip.srt writes scripts/clip.en.srt, scripts/clip.fr.srt, etc. Missing directories are created. Default: proofread.srt. Every language is always written — the URLs on the result are presigned and expire, and the files are the point.

  • The source language is always returned alongside the requested targets, so a one-language request writes two files.

  • After the files, the command prints the detected source language, the cue count, and one line per non-blocking warning (Warning fr: high_text_speed (warning) at cue 33 — ...). A warning never withholds a file.

  • Source videos may be at most 300 seconds long and 300 MB. Billing is per second of video multiplied by the number of target languages at $0.001/second, a transcript-only request counts as one, and billing has a 10-second floor; there are 2 free runs — see Free trial below.

  • --timeout defaults to 600 seconds, the usual default: a proofread job typically finishes in well under a minute. If the wait does time out, the task keeps running server-side — resume it with sonilo tasks wait <task-id>.

  • Edit the files, then feed them straight into dubbing, which makes the dub speak your exact wording (drop the source-language file: --subtitle must match --languages):

    sonilo proofread --video clip.mp4 --languages es,fr --output scripts/clip.srt
    # ... correct scripts/clip.es.srt and scripts/clip.fr.srt ...
    sonilo dubbing --video clip.mp4 --languages es,fr \
      --subtitle es=scripts/clip.es.srt --subtitle fr=scripts/clip.fr.srt
    

Dubbing

dubbing dubs a video into one or more target languages in a single async call:

sonilo dubbing --video-url https://example.com/clip.mp4 --languages es,fr --output dubbed.mp4
# writes dubbed.es.mp4 and dubbed.fr.mp4
  • --languages is comma-separated; omit it to use the server default zh_cn,es,fr. Supported codes: en, zh_cn, ja, ko, pt, pt_br, es, es_419, de, fr, it, ru, th, ar, tr, vi, id, ta, ml, kn, gu, pa_in, sd_in, hi (pt_br is Brazilian Portuguese and es_419 Latin American Spanish; plain pt and es stay unqualified, as does ar; pa_in and sd_in are Punjabi and Sindhi as spoken in India, the only variants available; hi is Hindi).

  • Source videos may be at most 300 seconds long.

  • --no-lipsync leaves the picture completely untouched. By default the speaker's mouth is re-rendered to match the dubbed speech; with this flag the video comes back at its original resolution and frame rate and only the audio is replaced, so the mouths keep moving to the original language. Use it for footage with no on-camera speaker, or when preserving the exact original picture matters more than matching lip movement.

  • --output is a filename template, not a single destination: a dubbing task returns one video per language, so --output clip.mp4 writes clip.es.mp4, clip.fr.mp4, etc.

  • --ducking ducks the background music/effects bed under the dubbed voice while it speaks; off by default, so the bed otherwise stays at a static level. --no-ducking states that default explicitly.

  • --subtitle <language>=<path-or-url> gives one language the script to speak, as an .srt/.vtt file or an https URL. Repeat it once per language; the set must match --languages exactly. The scripts are in the target language, not the source's:

    sonilo dubbing --video clip.mp4 --languages es,fr \
      --subtitle es=spanish.srt --subtitle fr=https://example.com/french.vtt --export-srt
    
  • --export-srt (requires --subtitle) returns a re-timed .srt per language, aligned to the delivered audio with your lines kept verbatim. Each one is written beside its video (clip.es.mp4 -> clip.es.srt), and one status line per language is printed. A language whose export is blocked still gets its video — only the .srt is missing.

  • Billing is per language, and dubbing has no free trial runs — see Free trial below.

  • --timeout defaults to 7200 seconds, matching the backend's own ceiling for a dubbing job (far longer than other commands' default, since dubbing can run well past the usual tasks wait --timeout 600). If the wait still times out, the task keeps running server-side — resume watching it with sonilo tasks wait <task-id>.

Free trial

Accounts created through self-serve signup start with free runs on most endpoints — no card required:

Free runs Endpoints
2 each text-to-music, text-to-sfx, audio-ducking, video-analysis, proofread
1 each video-to-music, video-to-sfx, video-to-video-music, video-to-video-sfx, video-to-sound, video-to-video-sound
0 dubbing

Dubbing bills video duration × number of languages, so a free run on it would be worth far more than a free run on any other endpoint — it has no free allowance and bills from the first call.

The table above is the current default. sonilo account prints the live numbers: the account JSON goes to stdout, and when the account has a free-trial allowance one summary line goes to stderr:

Free trial: text-to-music 1/2 left, video-to-music 0/1 left

Because the summary is on stderr, sonilo account | jq .trial still sees clean JSON.

Once an endpoint's free runs are used up, calls to it bill at the normal rate — or, if the account has never been funded, fail with HTTP 402: ... (trial_exhausted) until a payment method is added. That is the one 402 a retry can never fix.

Rate limits

Two separate limits return HTTP 429, and they want opposite handling. The CLI prints the API's own sentence, so the wording says which one you hit:

sonilo: HTTP 429: Rate limit exceeded: your account allows 60 requests per minute. Please retry after 1 minute. To raise your limit, please contact info@sonilo.com. (rate_limit_exceeded)
sonilo: HTTP 429: Too many concurrent generations: 5 of 5 in progress. Please wait for one to finish before starting another. To raise your limit, please contact info@sonilo.com. (rate_limit_exceeded)

The first means calls are going out too fast. The counter runs on a fixed 60-second window and rejected calls count toward it too, so wait the window out instead of retrying inside it. The second means every generation slot is busy — waiting alone frees nothing, a running generation has to finish first.

sonilo account prints the account's own rpm_limit and concurrency_limit; the numbers above are the standard-tier defaults. Email info@sonilo.com to raise either.

Release files for sonilo-cli 0.19.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sonilo-cli 0.19.0
File Size Uploaded
sonilo_cli-0.19.0.tar.gz 59.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sonilo-cli 0.19.0
File Interpreter ABI Platform
sonilo_cli-0.19.0-py3-none-any.whl Python 3 none any Details

Total release size: 92.3 kB

Release files / sonilo_cli-0.19.0.tar.gz

Download URL sonilo_cli-0.19.0.tar.gz
Size 59.7 kB
Tags Source
SHA-256 checksum
How to use checksums
8dfd7327a3d8ce7eb81ee49a711383ea20895cd9ed347a8561b1b823fd8b48a0
BLAKE2b-256 checksum
How to use checksums
ac3a5125dfa9782020e7a6a251639b5363907a9c3b8887a12db54c39f27cc0a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release files / sonilo_cli-0.19.0-py3-none-any.whl

Download URL sonilo_cli-0.19.0-py3-none-any.whl
Size 32.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f0ade75859d6ec9d9a32184e0566d271723f4c14fde776c193c18aa840e094d4
BLAKE2b-256 checksum
How to use checksums
b84498614f4ecd35af8a56902a7c45deb31893c8e03498750278515da050d90d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

0.20.0

2 release files

This release

0.19.0 This release

2 release files

0.18.0

2 release files

0.17.2

2 release files

0.17.1

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.14.3

2 release files

0.14.2

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page