Integration guides

Sync bank transactions to Postgres

One command. The SheetLink CLI connects to 10,000+ banks through Plaid and writes your transactions into a Postgres table, ready for dbt, Metabase, Tableau or any SQL tool you already use.

Free to install. CLI automation, Postgres and SQLite come with Max.

The SheetLink CLI syncs your transactions into Postgres or SQLite with Max.

How it works

Three steps from install to queryable transactions in Postgres.

1

Install the SheetLink CLI

A Node.js tool (Node 18 or later) for macOS, Linux and Windows.

npm install -g sheetlink
2

Authenticate

Sign in through your browser, or save a Max API key so scheduled runs never need a browser. Create keys in your SheetLink dashboard.

sheetlink auth                    # browser sign-in, lasts 4 hours
sheetlink auth --api-key sl_...   # Max API key, for unattended runs
3

Run the sync

One command writes your transactions to sheetlink_transactions and your accounts and balances to sheetlink_accounts. The CLI creates both tables on the first run and upserts on later runs, so there are no duplicates. Postgres output is part of Max.

sheetlink sync --output postgres://user:pass@host/db

Postgres table schema

SheetLink creates these tables on the first sync. The schema is stable across syncs, so your downstream SQL stays intact. The transactions table has the same 34 columns SheetLink writes to Google Sheets and Excel, plus category (Plaid’s older category list).

CREATE TABLE IF NOT EXISTS sheetlink_transactions (
  transaction_id           TEXT PRIMARY KEY,
  account_id               TEXT,
  persistent_account_id    TEXT,
  account_name             TEXT,
  account_mask             TEXT,
  date                     DATE NOT NULL,
  authorized_date          DATE,
  datetime                 TEXT,
  authorized_datetime      TEXT,
  description_raw          TEXT,
  merchant_name            TEXT,
  merchant_entity_id       TEXT,
  amount                   DECIMAL(10,2),
  iso_currency_code        TEXT,
  unofficial_currency_code TEXT,
  pending                  BOOLEAN,
  pending_transaction_id   TEXT,
  check_number             TEXT,
  category_primary         TEXT,
  category_detailed        TEXT,
  payment_channel          TEXT,
  transaction_type         TEXT,
  transaction_code         TEXT,
  location_address         TEXT,
  location_city            TEXT,
  location_region          TEXT,
  location_postal_code     TEXT,
  location_country         TEXT,
  location_lat             DECIMAL(10,7),
  location_lon             DECIMAL(10,7),
  website                  TEXT,
  logo_url                 TEXT,
  source_institution       TEXT,
  category                 TEXT,
  synced_at                TIMESTAMP DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS sheetlink_accounts (
  account_id            TEXT PRIMARY KEY,
  persistent_account_id TEXT,
  name                  TEXT,
  official_name         TEXT,
  mask                  TEXT,
  type                  TEXT,
  subtype               TEXT,
  current_balance       DECIMAL(10,2),
  available_balance     DECIMAL(10,2),
  iso_currency_code     TEXT,
  institution           TEXT,
  last_synced_at        TIMESTAMP DEFAULT NOW()
);

amount follows Plaid’s sign: positive is money out (purchases, fees), negative is money in (deposits, refunds). The CLI doesn’t create indexes, so add your own if you query by date or account:

CREATE INDEX IF NOT EXISTS idx_sheetlink_transactions_date
  ON sheetlink_transactions (date DESC);

CREATE INDEX IF NOT EXISTS idx_sheetlink_transactions_account_id
  ON sheetlink_transactions (account_id);

SheetLink uses INSERT ... ON CONFLICT (transaction_id) DO UPDATE, so running sheetlink sync again is safe and idempotent.

What to do with transactions in Postgres

BI tools (Metabase, Tableau, Superset)

Connect your BI tool directly to Postgres. Build dashboards showing monthly spend by category, cash flow over time or top merchants, all from your real bank data.

dbt models

Use the transactions table as a source in your dbt project. Write models to categorize spend, calculate rolling averages or join against other tables. The stable schema keeps your refs valid across syncs.

Custom analytics

Write SQL directly against the transactions table. Group by merchant, filter by date range, or work out account balances on any given day. No spreadsheet required.

Multi-user dashboards

If you manage finances for several entities (business units, clients, family members), each can sync into the same tables, told apart by account_name and source_institution, or into its own database on the same Postgres server.

Manual CSV vs. the SheetLink CLI

TaskManual CSV to PostgresSheetLink CLI
Connect bankLog in to each bank’s websiteOnce, through Plaid
Export dataDownload a CSV from each banksheetlink sync --output postgres://...
Handle multiple accountsA separate CSV per accountAll accounts in one command
Schema consistencyDifferent columns per bankSame schema every time
DeduplicationBy hand: check for duplicate rowsAutomatic, by upserting on transaction_id
Repeat monthlyThe full manual process againRun the same command again
AutomationCustom scripting requiredAdd it to cron or CI with a Max API key

Pricing

PlanPriceWhat you get
Free$01 bank, your last 7 days, Google Sheets
Pro$4.99/mo or $39.99/yrEvery bank you connect, up to 2 years of history, Google Sheets and Excel, priority support
Max$10.99/mo or $99/yrEverything in Pro, plus Postgres and SQLite output, CLI automation (API keys), investments, and Claude

Postgres output is part of Max. Compare every plan ›

Questions

How do I sync bank transactions to Postgres?

Install the SheetLink CLI with npm install -g sheetlink, authenticate with sheetlink auth (or save a Max API key with sheetlink auth --api-key for scheduled runs), then run sheetlink sync --output postgres://user:pass@host/db. The CLI creates the sheetlink_transactions and sheetlink_accounts tables automatically and upserts on transaction_id. Postgres output is part of Max.

What Postgres schema does SheetLink create?

A sheetlink_transactions table with 35 columns: the 34 columns SheetLink writes to Google Sheets and Excel (transaction_id as the upsert key, date, authorized_date, description_raw, merchant_name, amount, category_primary, category_detailed, all the location fields and more), plus category. It also creates a sheetlink_accounts table with each account’s name, mask, type, current and available balances, and institution.

Does SheetLink deduplicate transactions on each sync?

Yes. SheetLink uses transaction_id as a unique key and upserts (INSERT ... ON CONFLICT DO UPDATE). Running sync multiple times is safe: no duplicate rows are created.

What connection string format does SheetLink expect?

Pass the full connection string to the --output flag: sheetlink sync --output postgresql://user:password@host:5432/dbname (postgres:// works too). You can also pass $DATABASE_URL if that environment variable is set. SSL connections (Supabase, RDS and others) are configured with sslmode in the connection string.

Can I use SheetLink with a hosted Postgres service?

Yes. SheetLink works with any Postgres connection string, including Supabase, Neon, RDS, Heroku Postgres, PlanetScale (Postgres) and self-hosted instances.

What plan do I need for Postgres sync?

Postgres output is part of Max, at $10.99 a month or $99 a year. Max also includes SQLite output, CLI automation (API keys for scheduled runs), investments and Claude.

See it work.

Schedule sheetlink sync and send transactions to Postgres or SQLite. CLI automation is part of Max. About the CLI ›

Keep reading.

Your transactions, in your database.

Free to install. CLI automation, Postgres and SQLite come with Max.