CLI
esfera converts spatial audio masters to IAMF from the terminal, on the same API and SDK as everything else in this site. It checks the master on your machine before uploading, shows live stages while the job runs, downloads the result, and has stable exit codes and --json output so it works inside scripts and CI.
Install
@esfera/cli is not on npm yet. Until the first release, build it from the repository or install a tarball Esfera sends you. It needs Node 20 or later.
# in a checkout of the Esfera Developer Hub repository
pnpm install
pnpm -r build
node packages/cli/dist/index.js --versionRun it as node packages/cli/dist/index.js <command> until it is installed as esfera. Once the package is released the install will be npm install -g @esfera/cli.
Sign in
esfera loginlogin opens your browser, shows a code, and asks you to approve the sign-in on your Esfera account. The key it creates is stored on this machine and appears on your account's API keys page as a CLI key. The key is checked against the API before it is saved.
For CI and other machines with no browser, give it a key instead. Any of these works:
esfera login --key esf_sk_live_v1_…
echo "$KEY" | esfera login
ESFERA_API_KEY=esf_sk_live_v1_… esfera loginIf the host has no browser sign-in, login falls back to a masked prompt for the key. esfera logout forgets the stored key, and revokes it on the server only when browser sign-in created it. esfera status shows which key id and host this machine uses.
Commands
| Command | What it does |
|---|---|
esfera | With no arguments in a terminal, opens the interactive session. |
login | Signs in, as above. auth login is an alias. |
logout | Forgets the stored key. |
status | Which key id and host this machine uses. auth status is an alias. |
convert <file | folder> | Converts a master, or every master in a folder. |
conversions list | Your conversions, newest first. --status, --page, --page-size. |
conversions get <id> | One conversion. |
presets | The profiles and presets the encoder accepts, grouped by family, with what each declares. |
usage | How many of your plan's minutes you have used. |
Every command accepts --json, which prints machine output only. --help and --version work anywhere.
Convert
esfera convert master.wav --preset esfera --profile advanced-2 -o master.iamf| Option | Meaning |
|---|---|
--preset <id> | esfera (the default), youtube, bed714_3oa or oa3. |
--profile <id> | A writable profile id, or auto (the default), which lets the preset decide. |
--programme <n> | 0-based programme, when the ADM declares several. Without it, the first is used and a note says so. |
--normalization <n> | sn3d (the default, AmbiX), n3d or fuma, for ambisonic masters. It is refused for ADM. |
-o <file> | Where to write the IAMF. Defaults to the master's name with .iamf, beside the master. |
--json | Print one result object and nothing else. |
Before anything is uploaded, convert reads the master's header on your machine and refuses it, with exit code 2, if:
- it is not a WAV, RF64 or BW64 file;
- it has no ADM metadata and is not ambisonic (4, 9 or 16 channels), which makes it a plain WAV;
- it is longer than your account's per-file duration limit or larger than its per-file size limit, which it reads from
GET /v1/usage;
A first- or second-order ambisonic source paired with bed714_3oa or oa3 is also refused before upload, with exit code 1.
Then it uploads straight to storage (masters over 16 MiB go in parallel parts), shows the stages while it analyses and encodes, downloads the IAMF, and prints a summary. Press ^C to detach: the job keeps running on the server, and esfera conversions get <id> picks it up again.
A whole folder
Give convert a folder and it converts every WAV, BWF, W64 or RF64 file in it, with one preset and profile for all, with as many in flight as your account's concurrency limit allows.
esfera convert ./masters --preset youtube -o ./iamf-o must then be a folder, and defaults to the input folder. Masters that cannot go are named and skipped, the rest proceed, and --programme is ignored (each master converts its first programme). It prints a line per master as it finishes and a summary, and exits 0 only when every master is ready.
Interactive session
Run esfera with no arguments in a terminal. The prompt takes convert, presets, list, get <id>, open, login, logout, help and quit. convert walks you through the file, preset, profile and output one step at a time. Jobs run in the background and print a ✓ or ✗ line when they finish, with a terminal bell. The last ten masters are remembered. Press ^C twice within two seconds to quit; running jobs keep going on the server.
Turn the bell off with --no-bell, with ESFERA_NO_BELL=1, or with { "bell": false } in ~/.config/esfera/config.json.
Exit codes
They are the contract: half of this tool's use is inside someone else's script.
| Code | Meaning |
|---|---|
0 | Success. |
1 | Usage error. |
2 | Pre-flight refused the file. Nothing was uploaded. |
3 | The API refused, at any stage: quota, concurrency, a revoked key, a profile the encoder will not write. Also: not signed in. |
4 | The conversion failed, stalled (no progress for 5 minutes outside queued), or something unexpected happened. |
130 | Interrupted. The job keeps running; use esfera conversions get <id>. |
JSON output
With --json a command prints machine output to stdout and nothing else; progress and notes go to stderr.
| Command | Output |
|---|---|
convert | { "id", "output", "bytes", "outputProfile", "durationSec" } |
convert <folder> | One JSON object per master as it finishes: { "file", "ok", "id", "output", "bytes", "outputProfile" }, or { "file", "ok": false, "reason" }. |
conversions list | The array of conversions. |
conversions get | The conversion. |
presets | The GET /v1/presets response. |
usage | The GET /v1/usage response. |
status | { "keyId", "apiUrl", "source" } |
esfera convert master.wav --json | jq -r .output
esfera conversions list --status ready --json | jq 'length'Credentials and environment
The key you sign in with is stored in credentials.json under ~/.config/esfera (or $XDG_CONFIG_HOME/esfera). The directory is mode 0700 and the file 0600, and the key is never echoed. A key is never kept in a shell profile.
| Variable | Effect |
|---|---|
ESFERA_API_KEY | Overrides the stored key. Use it in CI. |
ESFERA_API_URL | Overrides the host, even a stored one. Without it a pasted test key (esf_sk_test_…) is stored against https://staging-api.esfera.audio and a live key against https://api.esfera.audio. Browser sign-in targets production unless this is set. |
ESFERA_NO_BELL | Any non-empty value silences the session bell. |
NO_COLOR | Plain text, no colour. |
COLORTERM=truecolor | The full brand colour ramp. |
Colour and the spinner are also off when stdout is not a terminal or TERM=dumb.
CI usage
Store the key as a secret, pass it as ESFERA_API_KEY, and read the result from --json. The exit code tells you what kind of failure to expect.
# GitHub Actions. `esfera` must be on the PATH of the runner.
- name: Convert master
env:
ESFERA_API_KEY: ${{ secrets.ESFERA_API_KEY }}
run: |
esfera convert masters/episode.wav \
--preset esfera --json -o out/episode.iamf | tee result.jsonesfera convert master.wav --json -o out.iamf
case $? in
0) echo "ok" ;;
2) echo "master refused before upload" ;;
3) echo "API refused (key, quota or concurrency)" ;;
4) echo "conversion failed" ;;
esacA key from ESFERA_API_KEY never needs esfera login. Pin the host with ESFERA_API_URL when a pipeline must run against staging.