A production-grade CLI for the Lemon Squeezy API — stores, products, orders, subscriptions, customers, discounts, and license keys.
A polished, production-grade command-line interface for Lemon Squeezy —
manage stores, products, orders, subscriptions, customers, discounts, license keys, checkouts,
and webhooks, and script it all with table/json/yaml/csv output, a --jq filter, named accounts,
retries, and an MCP server for AI agents.
Built with the cliwright playbook: a generic core
with thin resources, secrets in the OS keyring, idempotent-only retries, and a --dry-run that
prints the equivalent curl. Lemon Squeezy speaks JSON:API; lsqueezy
hides that envelope behind flat, table-friendly records and a --rel name=type:id flag for
relationships.
# Install script (macOS/Linux) — downloads the release binary, verifies its checksum
curl -fsSL https://raw.githubusercontent.com/jjuanrivvera/lemon-squeezy-cli/main/install.sh | sh
# Homebrew (tap)
brew install jjuanrivvera/lemon-squeezy-cli/lemon-squeezy-cli
# Go
go install github.com/jjuanrivvera/lemon-squeezy-cli@latest# 1. Authenticate (key is stored in the OS keyring, verified against /users/me)
lsqueezy auth login --api-key eyJ0eXAiOi...
# ...or, for CI / headless use:
export LEMONSQUEEZY_API_KEY=eyJ0eXAiOi...
# 2. Browse
lsqueezy stores list
lsqueezy products list --store-id 1 --all
lsqueezy orders get 12345 -o json
# 3. Act
lsqueezy customers create --set name=Acme --set email=ops@acme.co --rel store=stores:1
lsqueezy subscriptions cancel 9999
lsqueezy orders refund 12345 --amount 500
# 4. Inspect anything without sending it
lsqueezy subscriptions cancel 9999 --dry-run
# -> curl -X DELETE 'https://api.lemonsqueezy.com/v1/subscriptions/9999' \
# -H 'Authorization: Bearer REDACTED' -H 'Accept: application/vnd.api+json'| Resource | Verbs | Notes |
|---|---|---|
stores |
list, get | read-only |
products |
list, get | read-only |
variants |
list, get | read-only |
prices |
list, get | read-only |
files |
list, get | read-only |
customers |
list, get, create, update, archive | archive sets status=archived |
orders |
list, get, refund, generate-invoice | refund is irreversible |
order-items |
list, get | read-only |
subscriptions |
list, get, update, cancel | cancel = DELETE |
subscription-items |
list, get, update, current-usage | usage-based billing |
subscription-invoices |
list, get, refund, generate-invoice | |
usage-records |
list, get, create | |
discounts |
list, get, create, delete | |
discount-redemptions |
list, get | read-only |
license-keys |
list, get, update | |
license-key-instances |
list, get | read-only |
checkouts |
list, get, create | custom checkouts |
webhooks |
list, get, create, update, delete | full CRUD |
users |
me | the authenticated user |
license |
activate, validate, deactivate | License API (not JSON:API) |
Writes take attributes via --data (raw JSON or @file) and/or repeated --set key=value,
and relationships via repeated --rel name=type:id. The JSON:API envelope is added for you.
lsqueezy customers create --set name=Acme --set email=a@b.co --rel store=stores:1
lsqueezy webhooks create \
--data '{"url":"https://x.co/hook","events":["order_created","subscription_updated"]}' \
--rel store=stores:1
lsqueezy subscriptions update 9999 --set pause=null --dry-runlsqueezy orders list -o csv
lsqueezy products list -o yaml --columns id,name,status
lsqueezy subscriptions list --filter status=active --all
lsqueezy orders list --store-id 1 --limit 50 --sort -createdAtGlobal flags: -o/--output (table|json|yaml|csv), --jq <expr>, --columns, --filter,
--sort, --all, --limit, --page, --account, --base-url, --dry-run, --show-token,
--no-color, --quiet, -v/--verbose. Table color is on only for a TTY and honors NO_COLOR.
--jq runs a built-in gojq program over the result before
it renders, in any format:
lsqueezy orders list -o json --jq '.[].id'
lsqueezy orders list --jq '[.[] | {id, email: .user_email, total: .total_formatted}]'
lsqueezy stores get 1 -o json --jq '.total_sales'The License API works with just a license key (the store API key is optional), so it's safe to ship in customer-facing tooling:
lsqueezy license validate --key 38b1460a-5104-4067-a91d-77b872934d51
lsqueezy license activate --key 38b1460a-... --instance-name my-laptop
lsqueezy license deactivate --key 38b1460a-... --instance-id 1c0c...auth login|logout|status, config path|view|set|use|list-profiles, init, doctor,
completion, alias set|list|remove, api <METHOD> <PATH>, version.
# Run lsqueezy as an MCP server so an agent can drive the API
lsqueezy mcp start
# Generate agent safety rules from the live command tree
lsqueezy agent guard --host claude-code # refund/cancel/delete/deactivate denied, writes ask
lsqueezy agent guard --host codex
lsqueezy agent guard --host opencodeThe MCP surface excludes setup/secret commands (auth, config, --api-key, --show-token,
--account and its hidden --profile alias, --base-url) so an agent can't read the key or
switch accounts.
flag > env (LEMONSQUEEZY_*) > config file > default. Config lives at
$XDG_CONFIG_HOME/lemon-squeezy-cli/config.yaml (or ~/.lemon-squeezy-cli/config.yaml). The API
key is stored in the OS keyring (with an encrypted-file fallback for headless boxes), never in the
config file. A profile is an account, so the selector is --account: one machine can hold several
keys (e.g. a live key and a test-mode key) and switch between them —
lsqueezy --account test orders list (or LEMONSQUEEZY_ACCOUNT=test). --profile still works as
a hidden back-compat alias.
make build # build bin/lsqueezy
make check # fmt + vet + lint + test (local gate)
make verify # DETERMINISTIC gate: check + spec-check + spec-completeness + cover-check + dod
make judge # LLM-scored subjective gate (needs claude/codex; not part of verify)
make accept # full acceptance: verify + judge
make docs-build # regenerate the CLI reference and build the docs site (mkdocs, strict)
make setup-hooksmake verify is the token-free gate CI runs; make judge adds the one non-deterministic LLM
check, and make accept is both together (the build-acceptance gate).
The documentation is MkDocs (Material theme). make docs-gen
regenerates the per-command reference from the live CLI into docs/commands/, and
make docs-build builds the whole site (getting-started + user-guide + command reference).
Everything below is now shipped:
- Docs site —
mkdocs.yml+ getting-started and user-guide pages;make docs-buildpasses. -
--jqoutput filter — a global--jq <expr>(gojq) filters the result before rendering. - API completeness — the manifest wraps the full Lemon Squeezy API (Store + License API),
enumerated against the official SDK (59/59 methods; enforced by
make spec-completeness). - Deeper tests — broadened the
httptestmock coverage across the resource set (≥80% gate). - Per-account selector —
--account(with--profilekept as a hidden alias).
MIT — see LICENSE.