actual-budget-api-expert
SKILL.md
Actual Budget API
Integration with Actual Budget - an open-source personal finance app.
Prerequisites
Install the Actual API package:
npm install @actual-app/api
Quick Start
const api = require("@actual-app/api");
async function main() {
await api.init({
dataDir: "/path/to/actual-data",
serverURL: "https://actual.example.com", // Optional: for sync server
password: "your-password", // Optional: for sync server
});
await api.downloadBudget("budget-sync-id");
// Work with the budget...
const accounts = await api.getAccounts();
console.log(accounts);
await api.shutdown();
}
main();
API Overview
Initialization
init(config)- Initialize the API connectionshutdown()- Close the connection cleanlydownloadBudget(syncId, options?)- Download budget from sync serverloadBudget(syncId)- Load budget from local filegetBudgets()- List all budget filessync()- Synchronize with serverrunImport(budgetName, func)- Create budget with importer functionrunBankSync(accountId?)- Sync linked bank accounts
Budgets
getBudgetMonths()- Get all budget monthsgetBudgetMonth(month)- Get budget for specific month (YYYY-MM)setBudgetAmount(month, categoryId, amount)- Set budgeted amountsetBudgetCarryover(month, categoryId, flag)- Enable/disable carryoverholdBudgetForNextMonth(month, amount)- Hold funds for next monthresetBudgetHold(month)- Reset held funds
Transactions
importTransactions(accountId, transactions[])- Import with deduplicationaddTransactions(accountId, transactions[], runTransfers?, learnCategories?)- Add raw transactionsgetTransactions(accountId, startDate, endDate)- Get transactions in date rangeupdateTransaction(id, fields)- Update transaction fieldsdeleteTransaction(id)- Delete a transaction
Accounts
getAccounts()- Get all accountscreateAccount(account, initialBalance?)- Create new accountupdateAccount(id, fields)- Update account fieldscloseAccount(id, transferAccountId?, transferCategoryId?)- Close accountreopenAccount(id)- Reopen closed accountdeleteAccount(id)- Delete account permanentlygetAccountBalance(id, cutoff?)- Get account balancegetIDByName(type, name)- Look up ID by name
Categories
getCategories()- Get all categoriescreateCategory(category)- Create categoryupdateCategory(id, fields)- Update categorydeleteCategory(id)- Delete category
Category Groups
getCategoryGroups()- Get all category groupscreateCategoryGroup(group)- Create groupupdateCategoryGroup(id, fields)- Update groupdeleteCategoryGroup(id)- Delete group
Payees
getPayees()- Get all payeescreatePayee(payee)- Create payeeupdatePayee(id, fields)- Update payeedeletePayee(id)- Delete payeemergePayees(targetId, sourceIds[])- Merge multiple payeesgetPayeeRules(payeeId)- Get rules for a payee
Rules
getRules()- Get all rulesgetPayeeRules(payeeId)- Get rules for payeecreateRule(rule)- Create ruleupdateRule(rule)- Update rule (pass full RuleEntity with id)deleteRule(id)- Delete rule
Schedules
getSchedules()- Get all schedulescreateSchedule(schedule)- Create scheduleupdateSchedule(id, fields, resetNextDate?)- Update schedule (resetNextDate recalculates next occurrence)deleteSchedule(id)- Delete schedule
Data Types
Primitives
| Type | Format |
|---|---|
id |
UUID string |
month |
YYYY-MM |
date |
YYYY-MM-DD |
amount |
Integer (no decimals). $120.30 = 12030 |
Transaction Object
{
id: 'uuid', // Optional for create
account: 'account-id', // Required
date: '2024-01-15', // Required
amount: 12030, // Integer cents
payee: 'payee-id', // Optional (create only, overrides payee_name)
payee_name: 'Kroger', // Optional (create only)
imported_payee: 'KROGER #1234', // Optional
category: 'category-id', // Optional
notes: 'Groceries', // Optional
imported_id: 'bank-123', // Optional (for dedup)
transfer_id: 'uuid', // Optional (internal use)
cleared: true, // Optional
subtransactions: [] // Optional (for splits, create/get only)
}
Account Object
{
id: 'uuid',
name: 'Checking Account',
type: 'checking', // checking, savings, credit, investment, mortgage, debt, other
offbudget: false,
closed: false
}
Category Object
{
id: 'uuid',
name: 'Food',
group_id: 'group-uuid', // Required
is_income: false
}
Category Group Object
{
id: 'uuid',
name: 'Bills',
is_income: false,
categories: [] // Populated in get only
}
Payee Object
{
id: 'uuid',
name: 'Kroger',
transfer_acct: 'account-id', // If this payee is a transfer target
favorite: false
}
Common Patterns
Import Bank Transactions
const transactions = [
{
date: "2024-01-15",
amount: -4500, // Negative = expense
payee_name: "Netflix",
imported_id: "netflix-jan-2024-001",
},
];
const result = await api.importTransactions(accountId, transactions);
console.log("Added:", result.added);
console.log("Updated:", result.updated);
console.log("Errors:", result.errors);
Batch Operations
await api.batchBudgetUpdates(async () => {
await api.setBudgetAmount("2024-01", foodCategoryId, 50000);
await api.setBudgetAmount("2024-01", gasCategoryId, 20000);
await api.setBudgetAmount("2024-01", funCategoryId, 10000);
});
Split Transactions
await api.addTransactions(
accountId,
[
{
date: "2024-01-15",
amount: -12000,
payee_name: "Costco",
subtransactions: [
{ amount: -8000, category: foodCategoryId, notes: "Groceries" },
{ amount: -4000, category: householdCategoryId, notes: "Supplies" },
],
},
],
false,
false,
);
Create Transfer
// Find transfer payee for destination account
const payees = await api.getPayees();
const transferPayee = payees.find((p) => p.transfer_acct === targetAccountId);
await api.addTransactions(sourceAccountId, [
{
date: "2024-01-15",
amount: -100000,
payee: transferPayee.id, // This creates the transfer
},
]);
Close Account with Balance Transfer
// Close account, transferring balance to another account
await api.closeAccount(
oldAccountId,
targetAccountId, // Transfer balance here
categoryId, // Optional: category for the transfer (if off-budget)
);
Error Handling
Always wrap API calls in try-catch and ensure shutdown() is called:
async function main() {
try {
await api.init({ dataDir: "/path/to/data" });
// ... do work
} catch (err) {
console.error("Budget error:", err.message);
} finally {
await api.shutdown();
}
}
Querying Data (ActualQL)
Run custom queries for advanced filtering:
// Using aqlQuery (recommended)
const result = await api.aqlQuery({
table: "transactions",
select: ["date", "amount", "payee.name"],
where: {
date: { gte: "2024-01-01" },
amount: { lt: 0 },
},
});
// Using query builder
const result = await api.aqlQuery(
api
.q("transactions")
.filter({ account: "account-id" })
.select(["date", "amount", "payee"]),
);
Query Builder Methods: filter(), unfilter(), select(), calculate(), groupBy(), orderBy(), limit(), offset()
Bank Sync
Trigger automatic bank synchronization:
await api.runBankSync(accountId);
Utilities
Convert between decimal and integer amounts:
// Decimal to integer ($12.34 → 1234)
const integer = api.utils.amountToInteger(12.34);
// Integer to decimal (1234 → 12.34)
const decimal = api.utils.integerToAmount(1234);
Full API Reference
For complete method signatures and all fields, see references/api-reference.md.
Weekly Installs
10
Repository
tifandotme/dotfilesFirst Seen
Feb 2, 2026
Security Audits
Installed on
opencode9
amp9
openclaw8
gemini-cli8
claude-code8
github-copilot8