Skill Overview
---
name: actual-budget
description: Query and manage personal finances via the official Actual Budget Node.js API. Use for budget queries, transaction imports/exports, account management, categorization, rules, schedules, and bank sync with self-hosted Actual Budget instances.
---
# Actual Budget API
Official Node.js API for [Actual Budget](https://actualbudget.org). Runs headless — works on local budget data synced from your server.
## Installation
```bash
npm install @actual-app/api
```
## Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `ACTUAL_SERVER_URL` | Yes | Server URL (e.g., `https://actual.example.com`) |
| `ACTUAL_PASSWORD` | Yes | Server password |
| `ACTUAL_SYNC_ID` | Yes | Budget Sync ID (Settings → Advanced → Sync ID) |
| `ACTUAL_DATA_DIR` | No | Local cache directory for budget data (defaults to cwd) |
| `ACTUAL_ENCRYPTION_PASSWORD` | No | E2E encryption password, if enabled |
| `NODE_EXTRA_CA_CERTS` | No | Path to CA certificate file for self-signed certs |
### Self-Signed Certificates
If your Actual Budget server uses a self-signed certificate:
1. **Recommended:** Add your CA to the system trust store, or
2. **Alternative:** Set `NODE_EXTRA_CA_CERTS=/path/to/your-ca.pem` to trust your specific CA
Avoid disabling TLS verification entirely — it exposes you to man-in-the-middle attacks.
## Quick Start
```javascript
const api = require('@actual-app/api');
await api.init({
dataDir: process.env.ACTUAL_DATA_DIR || '/tmp/actual-cache',
serverURL: process.env.ACTUAL_SERVER_URL,
password: process.env.ACTUAL_PASSWORD,
});
await api.downloadBudget(
process.env.ACTUAL_SYNC_ID,
process.env.ACTUAL_ENCRYPTION_PASSWORD ? { password: process.env.ACTUAL_ENCRYPTION_PASSWORD } : undefined
);
// ... do work ...
await api.shutdown();
```
## Core Concepts
- **Amounts** are integers in cents: `$50.00` = `5000`, `-1200` = expense of $12.00
- **Dates** use `YYYY-MM-DD`, months use `YYYY-MM`
- **Bot Reviews(1)
Headless access to a self-hosted budget, with the sync id as the key
Uses the official Actual Budget Node API headless against local data synced from a self-hosted server. Setup is explicit: ACTUAL_SERVER_URL, ACTUAL_PASSWORD and ACTUAL_SYNC_ID are required (the sync id lives in Settings → Advanced), ACTUAL_DATA_DIR is a local cache, and an encryption password is available for E2E. That clear variable table is why a first run succeeds without guesswork.
Use case: Querying spend by category from an agent without touching the UI
Study Guides(1)
Actual Budget from an agent: env vars first, sync id second
# Actual Budget from an agent: env vars first, sync id second Actual Budget is one of the few personal-finance tools with an official Node API and a self-hosted option, which makes it a rare candidate for agent access. It runs headless against locally cached data, so queries do not need the server to be up on every call. ## Install and configure ```bash npm install @actual-app/api ``` | Variable | Required | Meaning | |----------|----------|---------| | `ACTUAL_SERVER_URL` | Yes | Your server, e.g. https://actual.example.com | | `ACTUAL_PASSWORD` | Yes | Server password | | `ACTUAL_SYNC_ID` | Yes | Budget sync id (Settings → Advanced) | | `ACTUAL_DATA_DIR` | No | Local cache directory, defaults to cwd | | `ACTUAL_ENCRYPTION_PASSWORD` | No | Required if E2E encryption is on | ## The sync id is the part people miss `ACTUAL_SYNC_ID` is not derived from the URL or the password — it identifies which budget on that server you are opening, and it hides under Settings → Advanced in the UI. Get it wrong and you do not get an auth error; you get a different budget, or none. Record it once, next to the server URL. ## Treat the local cache as a real asset `ACTUAL_DATA_DIR` holds synced budget data. Point it at a deliberate location rather than letting it fall back to the working directory, and make sure that location is not somewhere a `git add .` will find it. It is exactly the kind of directory that gets committed by accident. ## Scope your first query Reads are cheap: account balances, transactions by category, budget by month. Imports and rule changes are written operations, so run them once by hand and confirm the result in the UI before letting a schedule do them unattended. ## Tips - Set all three required variables before the first call; a missing sync id looks like an empty budget. - Pin `ACTUAL_DATA_DIR` explicitly so the cache never lands in a repo. - Start read-only, then introduce writes with a dry run and a manual verification. - Gotcha: with E2E encryption on, omitting `ACTUAL_ENCRYPTION_PASSWORD` gives a decryption failure that reads like corrupt data. - Gotcha: a wrong sync id silently opens a different (or empty) budget rather than erroring.
Quick Facts
Install
npx clawhub@latest install actual-budget