lemon-squeezy-cli

command module
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 7 Imported by: 0

README

lsqueezy

CI Release Coverage Go Reference Go version Ask DeepWiki Built with cliwright

A production-grade CLI for the Lemon Squeezy API — stores, products, orders, subscriptions, customers, discounts, and license keys.

Documentation · Commands


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

# 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

Quickstart

# 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'

Resources

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)

Creating & updating (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-run

Output & filtering

lsqueezy 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 -createdAt

Global 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'

License keys (License API)

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...

Meta commands

auth login|logout|status, config path|view|set|use|list-profiles, init, doctor, completion, alias set|list|remove, api <METHOD> <PATH>, version.

AI agents (MCP + guard)

# 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 opencode

The 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.

Configuration & precedence

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.

Development

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-hooks

make 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).

Docs site

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).

Roadmap

Everything below is now shipped:

  • Docs sitemkdocs.yml + getting-started and user-guide pages; make docs-build passes.
  • --jq output 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 httptest mock coverage across the resource set (≥80% gate).
  • Per-account selector--account (with --profile kept as a hidden alias).

License

MIT — see LICENSE.

Documentation

Overview

Command lsqueezy is a production-grade CLI for Lemon Squeezy.

main wires a cancellable context (signal.NotifyContext) so Ctrl-C cancels in-flight pagination and retry backoff, expands user aliases before cobra parses, and blank-imports the resources package so its init() self-registers every resource against the generic core.

Directories

Path Synopsis
Package commands wires the cobra command tree.
Package commands wires the cobra command tree.
internal
api
Package api is the generic HTTP core for the Lemon Squeezy API: one client + one generic Resource[T] power every resource.
Package api is the generic HTTP core for the Lemon Squeezy API: one client + one generic Resource[T] power every resource.
auth
Package auth stores the API key in the OS keyring, with an encrypted-file fallback for headless environments.
Package auth stores the API key in the OS keyring, with an encrypted-file fallback for headless environments.
config
Package config implements config precedence flag > env > config file > default, with named profiles for multi-account use.
Package config implements config precedence flag > env > config file > default, with named profiles for multi-account use.
output
Package output is the single renderer for every resource: table (default), json, yaml, csv.
Package output is the single renderer for every resource: table (default), json, yaml, csv.
update
Package update self-updates the CLI binary from its GitHub releases.
Package update self-updates the CLI binary from its GitHub releases.
version
Package version holds build metadata injected via -ldflags at build time.
Package version holds build metadata injected via -ldflags at build time.
Package resources registers every Lemon Squeezy resource (and the custom action verbs and singleton command groups) against the generic core.
Package resources registers every Lemon Squeezy resource (and the custom action verbs and singleton command groups) against the generic core.
tools
gendocs command
Command gendocs generates docs/commands/*.md from the cobra tree so the reference docs stay in lockstep with the CLI (the CI drift check fails if they diverge).
Command gendocs generates docs/commands/*.md from the cobra tree so the reference docs stay in lockstep with the CLI (the CI drift check fails if they diverge).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL