Fob
Browse the docs

Use the library

The npm package that installs the CLI is also a Node.js library. The CLI calls the same functions, so anything a command can do, your code can do.

npm install @finopsbricks/fob-actual

It's an ES module and needs Node.js 22 or later.

A client per budget#

import { fobActual } from '@finopsbricks/fob-actual';

const actual = fobActual({
  server_url: 'https://budget.example.com',
  session_token: process.env.ACTUAL_TOKEN,
  sync_id: '1b4e28ba-2fa1-41d2-883f-0016d3cca427',
  data_dir: '/var/cache/fob-actual/household',
  // encryption_password: '…',   // for an end-to-end encrypted budget
});

const accounts = await actual.accounts.list();
const balance = await actual.accounts.balance(accounts[0].id);
  • The library takes credentials only as arguments. It never reads environment variables or the CLI's config file.
  • data_dir is where the engine keeps its local copy of the budget. Use one folder per budget, and keep it private: it's a full copy, decrypted if the budget is encrypted.
  • sync_id is needed for everything except budgets.list().

Sessions and hold()#

Each call opens the budget (fetching the latest changes), does its work, syncs any writes, and closes. That's simple but repeats the open for every call. To make several calls share one open session, wrap them in hold():

const report = await actual.hold(async () => {
  const out = {};
  for (const a of await actual.accounts.list()) out[a.name] = await actual.accounts.balance(a.id);
  return out;
});

Writes inside hold() sync once, when it finishes.

The Actual engine allows one budget session per process. Don't run calls on two clients at the same time; for several budgets, use them one after another.

What's on the client#

NamespaceCovers
budgetsList budget files, months, a month's budget, set amounts, carryover, hold
accountsList, get, balance, create, update, close, reopen, delete
transactionsList by account and dates, add, import (duplicate detection and rules), update, delete
categories, categoryGroups, payees, tagsList, get, create, update, delete; merge payees
rules, schedulesList, get, create, update, delete
queryRun an ActualQL query

Plus serverVersion() and hold(fn). Amounts are Actual's integer minor units throughout.

Errors#

Failures throw ActualError (exported) with a code you can branch on, such as token-expired, network-failure, file-not-found or needs-key. The messages match the CLI's; see Troubleshooting.