copilot-money-cli
v0.2.0
Published
Unofficial CLI for copilot.money — log in with a browser session and query your account data over GraphQL
Readme
copilot-money-cli
Unofficial command-line tool for copilot.money. Log in with your existing browser session and query your account data over Copilot's GraphQL API from the terminal.
Not affiliated with Copilot. Uses your own credentials against your own account.
How auth works
Copilot's API (https://app.copilot.money/api/graphql) authenticates with a
Firebase ID token (Authorization: Bearer <token>). Those tokens expire
after ~1 hour, so instead of copying a token repeatedly, this CLI reads the
Firebase auth session your browser already stores. That session contains a
long-lived refresh token plus the Firebase API key, which the CLI uses to
mint fresh ID tokens automatically via Firebase's public securetoken endpoint.
You copy one value from the browser once; the CLI keeps itself logged in.
Install
pnpm install
pnpm build
npm link # optional: exposes `copilot-money` on your PATHOr run without linking via pnpm dev -- <command> (e.g. pnpm dev -- accounts).
Log in
Copilot's web app stores its Firebase session in IndexedDB (not localStorage), so grab it from there:
Open https://app.copilot.money and sign in.
Open DevTools (Cmd-Opt-I), Console tab.
Paste this, run it, then copy the JSON it prints:
(async () => { const db = await new Promise((ok, no) => { const r = indexedDB.open("firebaseLocalStorageDb"); r.onsuccess = () => ok(r.result); r.onerror = () => no(r.error); }); const all = await new Promise((ok, no) => { const r = db .transaction("firebaseLocalStorage", "readonly") .objectStore("firebaseLocalStorage") .getAll(); r.onsuccess = () => ok(r.result); r.onerror = () => no(r.error); }); const e = all.find((x) => x.fbase_key?.startsWith("firebase:authUser")); console.log(JSON.stringify(e.value)); })();Select and copy that printed JSON (Cmd-C).
Run
copilot-money loginand press Enter to confirm; it reads the JSON straight from your clipboard (no pasting into the terminal):copilot-money login
Non-interactive alternatives (handy for scripts, or if clipboard read is unavailable):
pbpaste | copilot-money login # pipe the copied JSON (macOS)
copilot-money login --file session.json # read from a file, then delete itCredentials are stored at ~/.config/copilot-money-cli/credentials.json
(directory 0700, file 0600). Run copilot-money logout to remove them.
Security note: that file holds your refresh token, so treat it like a password. It grants ongoing access to your Copilot account until you revoke the session (change your Copilot password / sign out everywhere).
Commands
All data commands print JSON to stdout, so they pipe cleanly into jq.
| Command | Description |
| ---------------------------- | ---------------------------------------------------------------------------- |
| copilot-money login | Store the browser session (--file <path> to read from a file) |
| copilot-money logout | Remove stored credentials |
| copilot-money whoami | Show the logged-in account and token status |
| copilot-money accounts | List accounts and balances (--type filter, repeatable) |
| copilot-money transactions | List transactions (filters below) |
| copilot-money summary | Transaction totals: count, income, spent, net (same server filters) |
| copilot-money categories | List categories and child categories |
| copilot-money networth | Net worth history (--timeframe) |
| copilot-money holdings | Investment holdings and securities |
| copilot-money introspect | Dump the live GraphQL schema (disabled in prod; see docs/schema.md) |
| copilot-money query [q] | Run any GraphQL operation (inline, --file, or stdin; --variables <json>) |
transactions flags
-n, --first <count>max to return (default 50; all in range with--from/--to)--account <id>(client-side) ·--category <id>·--tag <id>·--type <type>(all repeatable)--reviewed/--unreviewed·--recurring/--one-time--from <YYYY-MM-DD>/--to <YYYY-MM-DD>(inclusive, client-side)--sort DATE|AMOUNT·--dir ASC|DESC·--edges(raw single page)
Valid enum values are shown in --help. See docs/schema.md for what the API
does and does not support server-side (e.g. account/date filtering is client-side
because the server has no filter for them; summary therefore has no --account
or date range).
Examples
# Account balances
copilot-money accounts | jq '.[] | {name, balance}'
# Credit-card accounts only
copilot-money accounts --type CREDIT
# Income transactions in the first half of 2026
copilot-money transactions --type INCOME --from 2026-01-01 --to 2026-06-30 > income.json
# 200 most recent for one account, newest first
copilot-money transactions --account <accountId> -n 200
# Spend totals for a category
copilot-money summary --category <categoryId>
# Net worth over the last year
copilot-money networth --timeframe ONE_YEAR
# Run a custom query (strip @client fields — see docs/schema.md)
copilot-money query 'query { user { id termsStatus } }'Notes on custom queries
The built-in queries mirror Copilot's own Apollo operations but omit all
@client fields (computed in the browser and rejected by the server). If you
write your own via copilot-money query, strip any @client fields (e.g. Account
identifierId/status, Transaction datetime, Networth total). Introspection
is disabled in production, so docs/schema.md documents the recovered types,
enums, and filter behavior.
Development
pnpm dev -- <command> # run from source via tsx
pnpm typecheck
pnpm test # node:test, no build step
pnpm build # emit dist/