saasflow
v0.2.7
Published
Command-line client for the SaaSFlow public API.
Maintainers
Readme
saasflow
Command-line client for the SaaSFlow public API.
npm install -g saasflow
saasflow --helpSetup
Pick the path that matches your environment. They don't mix — each is self-contained.
Human path: saasflow login (persistent)
Best for daily-driver use on a workstation. One interactive login, then every command "just works".
saasflow login
# Opens your browser at api.saasflow.com/auth/oauth2/authorize, signs
# you in, asks you to consent. After login, lists the companies you
# have access to and asks which one to default to (or auto-picks if
# there's only one). Tokens + the chosen company land in
# ~/.saasflow/config.json (mode 0o600) and refresh automatically.
saasflow whoami
# → Authenticated via OAuth
# email: [email protected]
# company: Acme Inc (cmp_abc123)
saasflow companies use # change the default company (arrow-key picker)
saasflow companies use cmp_xyz # …or set it directly
saasflow logout # clears stored credentialsThe OAuth flow uses PKCE on a fixed saasflow-cli client — no client secret, no Dynamic Client Registration noise. You can untick Make changes to your SaaSFlow company data at consent time for a read-only session; in that case, write commands return 403 until you re-login with the box ticked.
Got an API key from the SaaSFlow web UI (Settings → API keys) and want it on the same persistent profile? Same command:
saasflow login --api-key sf_live_… # validates against /companies, then runs the picker
saasflow login --api-key - # …or read the key from stdinCI / scripted path: env vars (stateless)
Best for ephemeral environments — Docker containers, GitHub Actions, anywhere ~/.saasflow/config.json would be thrown away after the run. No login step needed.
env:
SAASFLOW_API_KEY: ${{ secrets.SAASFLOW_API_KEY }}
SAASFLOW_COMPANY_ID: cmp_abc123 # optional — or pass --company per command
run: |
saasflow companies list
saasflow data mrrAtDate --mrr-type cmrr --date 2026-04-30Each command reads SAASFLOW_API_KEY (and optionally SAASFLOW_COMPANY_ID / SAASFLOW_BASE_URL) at startup. No state file, no implicit cross-command persistence.
Pointing at staging / local
Both paths accept --base-url. For the human path, persist it on a named profile:
saasflow login --profile staging --base-url https://staging-api.saasflow.com
saasflow login --profile local --base-url http://localhost:3000
saasflow --profile staging companies listFor CI, set SAASFLOW_BASE_URL. Production end-users never need to touch it — https://api.saasflow.com is the default.
Precedence
When multiple sources resolve the same field, the order is:
explicit flag (--api-key, --company, --base-url, --profile)
> env var (SAASFLOW_API_KEY, SAASFLOW_COMPANY_ID, SAASFLOW_BASE_URL)
> profile's stored OAuth credentials
> profile's stored API keysaasflow whoami shows the resolved values and tags the line (override) if a flag or env var is shadowing the profile.
Examples
saasflow companies list
saasflow companies get cmp_abc123
saasflow transactions list --limit 50 --format table
saasflow transactions get tx_xyz
saasflow customers list --limit 100
saasflow search "stripe payout"
# Data slices — one subcommand per slice, with flags derived from the
# server's Zod schema. `--help` lists exactly what the API accepts.
saasflow data mrrAtDate --mrr-type cmrr --date 2026-04-30
saasflow data monthlyData --mrr-type recurring \
--start-date 2026-01-01 --end-date 2026-04-30 --format table
saasflow data periodDetails \
--start-date 2026-01-01 --end-date 2026-04-30 \
--date-definition cash --split-by counterparty
# Multiple slices in one round trip
saasflow data batch --from-json dashboard.jsonOutput
JSON to stdout by default — pipes cleanly into jq:
saasflow transactions list --limit 5 | jq '.[] | {id, amount}'Human-friendly tables:
saasflow transactions list --limit 5 --format table \
--columns id,date,amount,counterparty.nameProfiles
saasflow login --profile prod
saasflow login --profile staging --base-url https://staging-api.saasflow.com
saasflow --profile staging companies list
saasflow --profile prod data mrrAtDate --mrr-type cmrr --date 2026-04-30Each profile holds its own auth, base URL, and default company. --profile selects one for an invocation; otherwise the currentProfile field in ~/.saasflow/config.json decides.
Authentication
Three credential types are accepted, all passed as Authorization: Bearer <token>:
- OAuth access token — issued by
saasflow login. Carries the user's identity (auth.user.id), the granted scopes (saasflow:readand optionallysaasflow:write), and anaudclaim binding it to the SaaSFlow API. Refresh tokens auto-renew the access token; expired tokens are refreshed transparently on 401. - API key (
sf_…) — generate in the SaaSFlow web UI; scoped to a single company with explicit permissions. Best for unattended scripts and CI. Persist viasaasflow login --api-key …or pass per-process viaSAASFLOW_API_KEY/--api-key. - Firebase ID token — legacy, used by the SaaSFlow web app; not directly supported by the CLI.
The user's company role and per-grant scope both apply on every request — see the connector authorization model in the SaaSFlow Settings UI.
License
MIT
