Usage-based billing from your terminal. Send events, inspect how they were metered, and drive the Flexprice API without leaving the command line.
With the CLI, you can:
-
Send usage events and inspect how they were metered
-
Manage customers, subscriptions, invoices, and every other billing resource without leaving the terminal
-
Script against a stable JSON output contract and documented exit codes
-
Reach any API endpoint through the
get/post/deleteescape hatch, even ones without a named commandcurl -fsSL https://cli.flexprice.io | sh flexprice init
Install script (macOS, Linux)
curl -fsSL https://cli.flexprice.io | sh
Two environment variables tune it:
FLEXPRICE_VERSION=v1.0.1 sh install.sh # pin a release instead of latest
FLEXPRICE_INSTALL_DIR=~/bin sh install.sh # choose the install directory
Download a release (macOS, Linux, Windows)
Grab the archive for your platform from the latest release,
extract it, and put the flexprice binary on your PATH. This is the route
for Windows, which the install script doesn't cover.
Go
go install github.com/flexprice/cli/cmd/flexprice@latest
go install places the binary in $(go env GOPATH)/bin (commonly
~/go/bin) — if that directory isn't on your PATH, the install succeeds
silently but flexprice comes back "command not found" afterward. Check
and fix it with:
echo $PATH | tr ':' '\n' | grep "$(go env GOPATH)/bin" # prints nothing if missing
echo 'export PATH="$(go env GOPATH)/bin:$PATH"' >> ~/.zshrc # or ~/.bashrc
source ~/.zshrc
Upgrading: the CLI checks GitHub once a day and prints a notice when a
newer release exists. Run flexprice update to replace the binary in place
(--check only reports). Set FLEXPRICE_NO_UPDATE=1 to silence the notice.
On Windows, download the release by hand or re-run go install. Your config
and stored keys are untouched either way.
flexprice init walks you through picking a data region and pasting an API
key, verifies it against the API, and stores it in your OS keychain (or an
encrypted file when no keychain is available, e.g. in a container or CI).
$ flexprice init
███████╗██╗ ███████╗██╗ ██╗██████╗ ██████╗ ██╗ ██████╗███████╗
██╔════╝██║ ██╔════╝╚██╗██╔╝██╔══██╗██╔══██╗██║██╔════╝██╔════╝
█████╗ ██║ █████╗ ╚███╔╝ ██████╔╝██████╔╝██║██║ █████╗
██╔══╝ ██║ ██╔══╝ ██╔██╗ ██╔═══╝ ██╔══██╗██║██║ ██╔══╝
██║ ███████╗███████╗██╔╝ ██╗██║ ██║ ██║██║╚██████╗███████╗
╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═════╝╚══════╝
Usage-based billing from your terminal
Welcome to Flexprice — let's get you set up.
Your API key is scoped to one environment — you can add more later with `flexprice login`.
? Data region
> us https://us.api.flexprice.io/v1
in https://api.cloud.flexprice.io/v1
API key: ••••••••••••••••••••
⠹ Verifying your key…
✓ Verified — stored as profile "default" in encrypted file (~/.flexprice/keys)
Note: the API does not report which environment a key belongs to, so label your
profiles yourself (--profile-name, --label) and check with: flexprice whoami
Here's what to try first:
flexprice whoami confirm what you are pointed at
flexprice resources see everything you can act on
flexprice customers list try a read
flexprice env list see your other environments
The region menu is arrow-key driven. The wordmark drops to a compact form on
narrow terminals, and everything above is written to stderr, so it never
pollutes piped output. Pass --region and --api-key to skip both prompts
entirely in CI.
Confirm what you're pointed at:
$ flexprice whoami
Profile: default
Label:
Region: us
Base URL: https://us.api.flexprice.io/v1
Key backend: encrypted file (~/.flexprice/keys)
Key: sk_test_…4b
See everything you can act on:
$ flexprice resources
addons create, delete, list, lookup, retrieve, update
alert-settings create, delete, list, retrieve, update
alerts list
checkout create, delete, retrieve
costs active, analytics, analytics-v2, create, delete, list, retrieve, update
coupon-associations list, retrieve
coupons create, delete, list, lookup, retrieve, update
credit-grants create, delete, for-addon, for-plan, retrieve, update
credit-notes create, finalize, retrieve, void
customers by-external-id, create, delete, entitlements, entitlements-by-external-id, list, retrieve, subscriptions, upcoming-grants, update, usage
... and 24 more
197 commands across 34 resources are resolved at startup from the embedded OpenAPI spec. Nothing below is committed generated code (see ARCHITECTURE.md). A handful of commands don't map to a single API operation and are hand-written instead:
| Command | What it does |
|---|---|
flexprice init |
Guided first-run setup |
flexprice login / flexprice logout |
Add or remove a stored profile |
flexprice whoami |
Show the active profile, region, and key backend |
flexprice env list |
List environments in your tenant |
flexprice config list / flexprice config use <profile> |
Manage stored profiles |
flexprice resources |
List every resource and its actions |
flexprice <resource> <action> |
The generated surface, e.g. customers list, invoices finalize |
flexprice get / post / delete <path> |
Raw HTTP escape hatch for anything not covered by a resource command |
flexprice open dashboard / flexprice open webhooks |
Open the web dashboard or webhook portal |
flexprice version |
Print the CLI version and embedded spec build |
Every resource in the API is a top-level command, grouped by action:
flexprice customers list
flexprice customers retrieve cust_01K...
flexprice customers create --external_id=acme --email=billing@acme.com
flexprice invoices finalize inv_01K...
flexprice subscriptions cancel sub_01K...
For a request body too deep to express as flags (creating a subscription, for example), open it in your editor with the required fields pre-filled:
flexprice subscriptions create --edit
or supply it directly:
flexprice subscriptions create --data @subscription.json
subscriptions create --help shows exactly which fields flags can reach and
which cannot:
Fields you can set with flags:
--billing_period (required) [string]
--currency (required) [string]
--plan_id (required) [string]
... (23 more optional fields)
Nested fields — these cannot be set with flags:
addons [array]
line_items [array]
phases [array]
... (10 more)
Use --edit to fill in a pre-built request body, or --data @file.json.
Destructive actions (delete, void, cancel, terminate, archive,
finalize) ask for confirmation with an arrow-key prompt; --force skips it.
Off a terminal, the command refuses rather than proceeding (see
Running non-interactively).
Reads show a spinner while the request is in flight, and table output carries a footer naming which profile and region actually served it. That's the fastest way to catch "am I pointed where I think I am":
$ flexprice customers list
ID NAME STATUS CREATED_AT
cust_01J8XABCDEF Ada Lovelace active 2026-01-02
cust_02 Grace Hopper archived 2026-03-14
profile: default · region: us · sandbox · v1.0.0
A write confirms what it did, so you never have to infer success from a table:
$ flexprice customers create --external_id=acme --email=billing@acme.com
✓ Created customer cust_01J8XGHIJKL
An empty list points at the next step rather than saying nothing useful:
$ flexprice customers list
No customers yet.
Create one with: flexprice customers create
The footer, receipt and empty-state lines all go to stderr, so none of them appear in piped or redirected output.
Anything not covered by a named command is reachable through the raw escape hatch:
flexprice get /customers/cust_01K...
flexprice post /events --data @event.json
An API key belongs to exactly one environment. There is no --environment
flag, because the key itself already determines it. Switching environments
means switching profiles:
flexprice login --label "production" # stores a second profile
flexprice config list # see every stored profile
flexprice -p production customers list # use one for a single command
flexprice logout -p production # remove a profile and its key
flexprice env list shows every environment in your tenant, but the CLI
cannot tell you which one your active key belongs to: the API itself does not
expose that.
flexprice customers list --output json > customers.json
Data always goes to stdout; progress messages, warnings, and footers always go to stderr, so redirecting stdout never mixes the two. Exit codes are stable and safe to script against:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Generic failure |
| 2 | Usage error |
| 3 | Authentication failure |
| 4 | Not found |
| 5 | Rate limited |
| 130 | Interrupted (Ctrl-C) |
The CLI adapts to whether a human is watching. Progress animation is suppressed
automatically when stderr is not a terminal, when TERM=dumb, and under
--quiet, so CI logs stay clean without any flag. Colour additionally respects
NO_COLOR and --no-color.
| Flag | Effect |
|---|---|
--quiet |
Suppress progress and commentary. Results and errors still print. |
--no-color |
Disable colour. Status icons (✓ ✗ ⚠) remain. |
--no-input |
Never prompt. Fail with a message naming the flag to pass instead. |
--force |
Skip the confirmation on destructive commands. |
Destructive commands (delete, void, cancel, terminate, archive,
finalize) confirm before acting. In a script, pass --force to proceed:
flexprice customers delete cust_123 --force
Without it, a non-interactive run fails rather than proceeding: the CLI will not destroy something because nobody could be asked.
Non-secret settings live in ~/.flexprice/config.toml; API keys live in your
OS keychain (or an encrypted file fallback where no keychain is available).
FLEXPRICE_API_KEY and --api-key override the stored key for a single
invocation or for CI.
flexprice <resource> --help
lists every action for a resource; a generated reference for every command is published at https://docs.flexprice.io/docs/cli/overview.
This CLI dispatches commands at runtime from an embedded OpenAPI spec rather than generating Go source per command; ARCHITECTURE.md walks through the request lifecycle end to end. The two most common maintenance tasks (adding a generated command and adding a hand-written one) are walked through in guides/.
Build and test locally with the standard Go toolchain, or via make.
make help lists every target (build, test, lint, docs, smoke/e2e suites,
release):
go build ./...
go test -race ./...
make check # build, vet, test, lint, same as CI
Pull requests and issues are welcome directly against this repository. See CONTRIBUTING.md for dev setup, testing, and linting, and CODE_OF_CONDUCT.md for community standards.
Apache-2.0. See LICENSE.