CLI Reference
MAXThe sheetlinkCLI lets you sync bank transactions from the command line, pipe JSON to other tools, and automate syncs via cron. It’s a MAX-tier feature.
Overview
The CLI is an npm package that communicates with the SheetLink API. It’s designed for three primary use cases:
- Cron automation: Run unattended nightly syncs that write to Postgres or SQLite without any human involvement. MAX API keys never expire, making them ideal for cron jobs.
- ETL pipelines: Pipe the JSON output into jq, pandas, or any data tool. SheetLink becomes a read-only bank data source in your pipeline.
- CSV snapshots: Download a flat CSV of all your transactions on demand. Great for importing into other tools or archiving.
Installation
Install the sheetlink package globally via npm or your preferred package manager:
npm
npm install -g sheetlinkyarn
yarn global add sheetlinkpnpm
pnpm add -g sheetlinkVerify the installation:
$ sheetlink --version
0.1.15Node.js requirement: The CLI requires Node.js 18 or later. Check your version with node --version.
Authentication
The CLI supports two authentication methods. Which one to use depends on your use case.
OAuth (Pro + MAX)
InteractiveOpens your browser for Google sign-in. The resulting JWT is saved to ~/.sheetlink/config.json and used for subsequent commands. JWTs expire after approximately 1 hour.
sheetlink authBest for: interactive use, one-off commands, development workflows.
Not suitable for cron: JWTs expire ~1 hour after sign-in. If your cron job runs after the JWT expires, it will fail. Use an API key for cron automation.
API Key (MAX only)
MAXNever expiresAPI keys are long-lived credentials that never expire. They’re ideal for automation. Pass the key via the --api-key flag or set the SHEETLINK_API_KEY environment variable.
sheetlink auth --api-key sl_live_your_key_hereThis saves the key to ~/.sheetlink/config.json. After this, all commands use the API key automatically.
Security tip
Avoid passing --api-key directly in commands that end up in your shell history. Instead, use the SHEETLINK_API_KEY environment variable:
export SHEETLINK_API_KEY=sl_live_your_key_here
sheetlink syncOr for cron, set it inline in the crontab (see Cron & Automation).
Managing API KeysMAX
API keys are generated in the SheetLink dashboard. You can create multiple keys (e.g., one per automation script) and revoke them individually.
Open the SheetLink Dashboard
Go to sheetlink.app/dashboard and sign in.
Navigate to API Keys
In the dashboard sidebar, click API Keys.
Create a new key
Click New API Key, give it a descriptive name (e.g., “cron-nightly”), and copy the key immediately — it is only shown once.
Revoke a key
Click the trash icon next to any key to permanently revoke it. Any automation using that key will immediately stop working.
API keys look like: sl_live_xxxxxxxxxxxxxxxxxxxxxxxx. Keep them secret — treat them like passwords.
sheetlink sync
The primary command. Fetches all transactions from your connected banks and outputs them in the format you specify.
| Flag | Type | Description | Default |
|---|---|---|---|
--output <dest> | string | Output destination. One of: json, csv, postgres://<connstr>, sqlite:///<path> | json |
--file <path> | string | File path when using --output csv. If omitted, writes to ./sheetlink-transactions.csv | ./sheetlink-transactions.csv |
--item <item_id> | string | Sync only the specified bank item (use sheetlink items to find item_id values) | all items |
Examples
JSON to stdout (default)
sheetlink syncCount transactions with jq
sheetlink sync | jq '.items[].transactions | length'CSV snapshot to default path
sheetlink sync --output csvCSV to custom path
sheetlink sync --output csv --file ~/finances.csvPostgres upsert MAX
sheetlink sync --output postgres://localhost/mydbSQLite upsert MAX
sheetlink sync --output sqlite:///~/finance.dbSync one bank only
sheetlink sync --item VBX93wmRY4Iy...sheetlink items
Lists all bank items (connected institutions) on your account. Use this to find item_id values for use with sheetlink sync --item.
sheetlink itemsExample output:
item_id institution
─────────────────────────────────────────────────
VBX93wmRY4Iy3kPqD7z8mN Chase
KMN12xyzAB34cDeFGh5iJkL Bank of America
PLQ98pqrST56uVwXYz7aBC9 Wells Fargosheetlink auth
Authenticates the CLI. Without flags, opens a browser for Google OAuth. With --api-key, saves an API key instead.
| Flag | Type | Description |
|---|---|---|
--api-key <key> | string | Save a MAX API key to config. Skips browser OAuth flow. |
--logout | boolean | Remove stored credentials from config file. |
Browser OAuth (interactive)
sheetlink authSave API key
sheetlink auth --api-key sl_live_your_key_hereSign out
sheetlink auth --logoutsheetlink config
View and set persistent configuration values. Config is stored at ~/.sheetlink/config.json.
Show current config
sheetlink configSet default output format
sheetlink config --set default_output=csvSet default output to Postgres
sheetlink config --set default_output=postgres://user:pass@host/dbnameChange API URL (advanced)
sheetlink config --set api_url=https://api.sheetlink.appConfig keys
| Key | Description | Default |
|---|---|---|
default_output | Default output format when --output is not specified | json |
api_url | SheetLink backend URL | https://api.sheetlink.app |
api_key | MAX API key (set via sheetlink auth --api-key) | — |
The config file is plain JSON at ~/.sheetlink/config.json. You can edit it directly if needed.
Output Formats
JSON (default)
The default output. A structured JSON object is written to stdout, making it composable with any Unix tool. Nothing is written to disk unless you redirect the output.
Output shape:
{
"synced_at": "2026-04-09T08:00:00.000Z",
"items": [
{
"item_id": "VBX93wmRY4Iy...",
"institution_name": "Chase",
"accounts": [
{
"account_id": "acc_abc123",
"name": "Chase Checking",
"mask": "4242",
"type": "depository",
"subtype": "checking",
"balances": {
"current": 2847.12,
"available": 2647.12
}
}
],
"transactions": [
{
"transaction_id": "txn_xyz789",
"date": "2026-04-08",
"name": "Whole Foods Market",
"amount": 47.23,
"category": "Food and Drink",
"account_id": "acc_abc123",
"account_name": "Chase Checking",
"account_mask": "4242",
"institution_name": "Chase",
"pending": false,
"payment_channel": "in store",
"merchant_name": "Whole Foods Market",
"primary_category": "FOOD_AND_DRINK",
"detailed_category": "FOOD_AND_DRINK_GROCERY_STORES"
}
]
}
]
}Pipe examples:
# Get all transaction names
sheetlink sync | jq '[.items[].transactions[].name]'
# Sum all transaction amounts
sheetlink sync | jq '[.items[].transactions[].amount] | add'
# Filter by merchant
sheetlink sync | jq '.items[].transactions[] | select(.merchant_name == "Amazon")'CSV
Writes a flat CSV file. Each sync overwrites the file — it’s a point-in-time snapshot, not an append log. The default output path is ./sheetlink-transactions.csv.
CSV columns (in order):
sheetlink sync --output csv --file ~/finances.csvPostgresMAX
Upserts transactions and accounts into a Postgres database. Tables are created automatically on first run. Safe to run repeatedly — deduplication is handled by transaction_id and account_id.
sheetlink sync --output postgres://user:password@host:5432/dbnameAuto-created schema:
-- Transactions table
CREATE TABLE IF NOT EXISTS sheetlink_transactions (
transaction_id TEXT PRIMARY KEY,
date DATE NOT NULL,
name TEXT,
amount NUMERIC(12, 2),
category TEXT,
account_id TEXT,
account_name TEXT,
account_mask TEXT,
institution_name TEXT,
pending BOOLEAN,
payment_channel TEXT,
merchant_name TEXT,
primary_category TEXT,
detailed_category TEXT,
synced_at TIMESTAMPTZ DEFAULT NOW()
);
-- Accounts table
CREATE TABLE IF NOT EXISTS sheetlink_accounts (
account_id TEXT PRIMARY KEY,
name TEXT,
mask TEXT,
type TEXT,
subtype TEXT,
institution_name TEXT,
balance_current NUMERIC(12, 2),
balance_available NUMERIC(12, 2),
synced_at TIMESTAMPTZ DEFAULT NOW()
);Upsert behavior: SheetLink uses INSERT ... ON CONFLICT DO UPDATE so rows are safely overwritten if transaction data changes (e.g., a pending transaction settles and the amount changes).
SQLiteMAX
Same schema as Postgres, but written to a local SQLite file. No server required — great for local development, personal finance dashboards, or lightweight automation.
sheetlink sync --output sqlite:///~/finance.dbThe file is created if it doesn’t exist. The same sheetlink_transactions and sheetlink_accounts tables are created with identical schema.
Environment Variables
Environment variables override values in ~/.sheetlink/config.jsonand are useful for CI/CD, Docker, and cron environments where you don’t want to rely on a home-directory config file.
| Variable | Description |
|---|---|
SHEETLINK_API_KEYMAX | API key for authentication. Overrides api_key in config file. Use this instead of --api-key to keep keys out of shell history. |
SHEETLINK_OUTPUT | Default output format. Overrides default_output in config file. Accepts same values as --output. |
SHEETLINK_API_URL | SheetLink API base URL. Overrides api_url in config file. Useful for self-hosted setups. |
Using env vars in practice:
# Set once in your shell profile
export SHEETLINK_API_KEY=sl_live_your_key_here
export SHEETLINK_OUTPUT=postgres://user:pass@host/mydb
# Then sync is just:
sheetlink syncCron & AutomationMAX
The most powerful SheetLink use case: an unattended nightly sync that keeps your database or CSV always up to date. This requires a MAX plan because cron jobs need credentials that never expire — API keys, not JWTs.
Important: OAuth JWTs from sheetlink auth expire after approximately 1 hour. A cron job running after expiry will fail with an authentication error. Always use a MAX API key for cron.
Crontab example
Run crontab -e and add:
# Sync bank transactions to Postgres every day at 8am
0 8 * * * SHEETLINK_API_KEY=sl_live_your_key_here sheetlink sync --output postgres://user:pass@host/db >> ~/sheetlink.log 2>&1Sync to SQLite at 6am daily
0 6 * * * SHEETLINK_API_KEY=sl_live_your_key_here sheetlink sync --output sqlite:///home/user/finance.db >> ~/sheetlink.log 2>&1Sync to CSV every hour
0 * * * * SHEETLINK_API_KEY=sl_live_your_key_here sheetlink sync --output csv --file /data/transactions/latest.csv 2>&1Docker / CI example
# In your Dockerfile or CI config, pass the key as an env var
docker run --rm \
-e SHEETLINK_API_KEY=sl_live_your_key_here \
-e SHEETLINK_OUTPUT=postgres://user:pass@host/db \
node:20-alpine \
sh -c "npx sheetlink sync"Logging
The CLI writes status messages to stderr and data to stdout. Redirect both for complete logs:
# Capture both stdout (data) and stderr (logs)
sheetlink sync --output postgres://... >> ~/sheetlink-data.log 2>> ~/sheetlink-errors.log
# Or combine both into one file
sheetlink sync --output postgres://... >> ~/sheetlink.log 2>&1Quick start checklist for cron
- Upgrade to MAX tier at sheetlink.app/pricing
- Create an API key in the dashboard (Dashboard → API Keys → New API Key)
- Verify the key works: SHEETLINK_API_KEY=sl_... sheetlink sync
- Set up your target database (Postgres) or confirm the CSV path is writable
- Add the crontab entry
- Monitor ~/sheetlink.log after the first run