@mostlydev/wave-cli
v0.1.0
Published
Read-only Wave Accounting export and reporting CLI for bookkeeping workflows.
Maintainers
Readme
wave-cli
Read-only Wave Accounting export and reporting CLI.
The useful first target is not "post accounting changes"; it is reliable pulls: revenue, expenses, uncategorized rows, transaction line items, and Wave-calculated report packages that can feed tax returns, annual reports, and forecasts.
Why Browser Auth
Wave's official public API is OAuth based and uses
https://gql.waveapps.com/graphql/public. Its current scopes include read
access for businesses, accounts, customers, invoices, products, sales taxes,
users, and vendors, plus transaction write scopes. The public schema exposes
invoice data and manual invoice-payment mutations, but the bookkeeping notes
show that the export/reporting work needs the web app's transaction list,
Reports tab, and existing bank-feed rows. This CLI starts with the logged-in
Wave web app because that is the surface that has the transaction data and
report calculations we need.
Auth is local:
wave auth loginreads the Wave password from 1Password withop.- Login, Wave business, and 1Password item settings live in
~/.config/wave-cli/config.env. - The operator still approves MFA/device prompts in the visible browser.
- Browser session state stays under
~/.local/state/wave-cli/browser-profile. - Internal GraphQL headers are captured from live browser requests and used in memory only. Report commands navigate Wave's Reports tab and capture the report response that Wave itself calculated.
- After login, pull and report commands reuse that profile headlessly by
default. Pass
--visibleto debug a command in a browser window.
Install
From npm after publishing:
npm install -g @mostlydev/wave-cli
wave --versionFrom GitHub before an npm release:
npm install -g github:mostlydev/wave-cli
wave --versionFor local development:
npm install
npm link
npm run check
npm testThe CLI requires Node 22+, the 1Password CLI (op), and a Playwright-compatible
Chromium install. If Playwright reports that Chromium is missing, run:
npx playwright install chromiumLocal Configuration
Create the home-scoped config file:
wave config initThe file uses dotenv syntax and lives at ~/.config/wave-cli/config.env by
default. Required values:
WAVE_CLI_BUSINESS_URL=
WAVE_CLI_BUSINESS_ID=
WAVE_CLI_EMAIL=
WAVE_CLI_OP_REF=
WAVE_CLI_OP_ITEM=
WAVE_CLI_OP_VAULT=
WAVE_CLI_OP_FIELD=passwordUse either WAVE_CLI_OP_REF or the WAVE_CLI_OP_ITEM/WAVE_CLI_OP_VAULT
pair. Keep real account names, email addresses, Wave business IDs, and
1Password item names in the home config file only.
Inspect the active paths without printing secret values:
wave config pathsEnvironment variables override the config file. For a one-off alternate config,
set WAVE_CLI_CONFIG_FILE=/path/to/config.env. Existing installs can still read
legacy ~/.wave-cli/.env, but the CLI does not read .env from the current
working directory.
Login
wave auth loginWhat this does:
- Opens a visible local Chromium profile at
~/.local/state/wave-cli/browser-profile. - Navigates to the configured Wave transactions page.
- Fills the Wave email and password from 1Password when the login form is visible.
- Waits while the operator completes MFA/device approval in the browser.
- Captures the Wave app's live internal GraphQL auth headers in memory only to confirm the session works.
What this does not do:
- It does not print, export, or commit cookies.
- It does not write bearer tokens, GraphQL headers, passwords, OTPs, or HAR files.
- It does not store the 1Password password anywhere;
opis called at runtime.
The persistent browser profile will naturally contain normal browser session state, the same way Chrome keeps a signed-in session. Keep it local and do not copy it into a repo or handoff bundle.
For existing installs, ~/.wave-cli/browser-profile is detected automatically
when the new state path does not exist.
Useful overrides:
wave auth login --op-ref 'op://Vault/Item/password'
wave auth login --op-item 'Item name' --op-vault 'Vault name'
wave auth login --email [email protected]Check an existing browser session:
wave auth doctorIf auth doctor times out, the local profile is not signed in or Wave did not
emit an authenticated internal GraphQL request. Run wave auth login in a
visible browser and approve the Wave/MFA prompt on the computer.
Pull Data
Pull transactions for a year:
wave pull transactions --year 2026 --format csv -o exports/2026-transactions.csvPull one row per category/account line:
wave pull line-items --year 2026 --format csv -o exports/2026-line-items.csvPull raw report-supporting slices:
wave pull revenue --year 2026 --format csv -o exports/2026-revenue.csv
wave pull expenses --year 2026 --format csv -o exports/2026-expenses.csv
wave pull uncategorized --year 2026 --format csv -o exports/2026-uncategorized.csv
wave pull postings --year 2026 --format csv -o exports/2026-postings.csvCreate a tax/reporting package:
wave pull tax-package --year 2026 --dir exports/tax-2026That writes raw transaction/export files:
transactions.csvline-items.csvledger-postings.csvledger-postings-through-as-of.csvrevenue.csvexpenses.csvuncategorized.csvmanifest.json
Reports
Report commands use Wave's actual Reports tab. The browser opens the report route, Wave calculates the statement, and the CLI serializes the report response.
Generate reports for arbitrary periods or as-of dates:
wave report list
wave report pnl --from 2026-01-01 --to 2026-06-30 -o exports/pnl.json
wave report pnl --from 2026-01-01 --to 2026-06-30 --format csv --table summary -o exports/pnl-summary.csv
wave report balance-sheet --as-of 2026-06-30 --format csv -o exports/balance-sheet.csv
wave report trial-balance --as-of 2026-06-30 --format csv -o exports/trial-balance.csv
wave report package --from 2026-01-01 --to 2026-06-30 --dir exports/report-2026-h1CSV output can use --table detailed, --table summary, or --table overview.
JSON output preserves the full Wave report payload plus CLI metadata. The
compatibility command wave pull pnl now delegates to wave report pnl instead
of deriving a statement locally.
The report package writes:
profit-and-loss.jsonprofit-and-loss-detailed.csvprofit-and-loss-summary.csvprofit-and-loss-overview.csvbalance-sheet.jsonbalance-sheet-detailed.csvbalance-sheet-summary.csvbalance-sheet-overview.csvtrial-balance.jsontrial-balance-detailed.csvtrial-balance-summary.csvtrial-balance-overview.csvmanifest.json
Classification Rules
The export keeps raw transaction, line-item, and generated posting files so the
source data is visible. Raw revenue and expense pulls use Wave account metadata
(INCOME, EXPENSE, ASSET, LIABILITY, EQUITY) instead of category-name
guessing. Financial statement commands use Wave's Reports tab calculations.
Use raw line-items.csv and Wave-calculated reports together for accountant
review.
Safety
This CLI is read-only. It does not implement categorization, invoice-payment, transfer-link, split, or journal-entry save commands. Those workflows need an approval and verification layer before becoming CLI mutations.
Publishing
The package is scoped as @mostlydev/wave-cli and configured for public npm
publishing. Maintainer workflow:
npm run check
npm test
npm publish --dry-run
npm publishnpm publish runs the same checks through prepublishOnly. The package is
marked UNLICENSED; add an explicit license before treating this as an
open-source release.
Sources
- Wave OAuth guide: https://developer.waveapps.com/hc/en-us/articles/360019493652-OAuth-Guide
- Wave OAuth scopes: https://developer.waveapps.com/hc/en-us/articles/360032818132-OAuth-Scopes
- Wave public API schema reference: https://developer.waveapps.com/hc/en-us/articles/360019968212-API-Reference
