OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  actual-budget:通过 Actual 官方接口管理个人财务与预算

actual-budget:通过 Actual 官方接口管理个人财务与预算

 
  hash ·  2026-02-05 04:39:34 · 3 次点击  · 0 条评论  

名称: actual-budget
描述: 通过官方 Actual Budget Node.js API 查询和管理个人财务。可用于预算查询、交易导入/导出、账户管理、分类、规则、计划任务,以及与自托管 Actual Budget 实例的银行同步。


Actual Budget API

Actual Budget 的官方 Node.js API。以无头模式运行,适用于从服务器同步的本地预算数据。

安装

npm install @actual-app/api

环境变量

变量 是否必需 描述
ACTUAL_SERVER_URL 服务器 URL (例如 https://actual.example.com)
ACTUAL_PASSWORD 服务器密码
ACTUAL_SYNC_ID 预算同步 ID (设置 → 高级 → 同步 ID)
ACTUAL_DATA_DIR 预算数据本地缓存目录 (默认为当前工作目录)
ACTUAL_ENCRYPTION_PASSWORD 端到端加密密码 (如果启用)
NODE_EXTRA_CA_CERTS 自签名证书的 CA 证书文件路径

自签名证书

如果你的 Actual Budget 服务器使用自签名证书:

  1. 推荐: 将你的 CA 添加到系统信任存储中,或者
  2. 替代方案: 设置 NODE_EXTRA_CA_CERTS=/path/to/your-ca.pem 以信任特定的 CA

避免完全禁用 TLS 验证——这会让你暴露于中间人攻击的风险中。

快速开始

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
);

// ... 执行操作 ...

await api.shutdown();

核心概念

  • 金额 以分为单位的整数:$50.00 = 5000-1200 = 支出 $12.00
  • 日期 使用 YYYY-MM-DD 格式,月份使用 YYYY-MM
  • ID 是 UUID——使用 getIDByName(type, name) 按名称查找
  • 使用 api.utils.amountToInteger(123.45) 进行转换 → 12345

常用操作

获取预算概览

const months = await api.getBudgetMonths();        // ['2026-01', '2026-02', ...]
const jan = await api.getBudgetMonth('2026-01');   // { categoryGroups, incomeAvailable, ... }

账户

const accounts = await api.getAccounts();
const balance = await api.getAccountBalance(accountId);
const newId = await api.createAccount({ name: 'Checking', type: 'checking' }, 50000); // 初始金额 $500
await api.closeAccount(id, transferToAccountId);  // 转移剩余余额

交易

// 获取指定日期范围内的交易
const txns = await api.getTransactions(accountId, '2026-01-01', '2026-01-31');

// 导入交易(带去重和规则应用,推荐用于银行导入)
const { added, updated } = await api.importTransactions(accountId, [
  { date: '2026-01-15', amount: -2500, payee_name: 'Grocery Store', notes: 'Weekly run' },
  { date: '2026-01-16', amount: -1200, payee_name: 'Coffee Shop', imported_id: 'bank-123' },
]);

// 更新交易
await api.updateTransaction(txnId, { category: categoryId, cleared: true });

分类与收款方

const categories = await api.getCategories();
const groups = await api.getCategoryGroups();
const payees = await api.getPayees();

// 创建
const catId = await api.createCategory({ name: 'Subscriptions', group_id: groupId });
const payeeId = await api.createPayee({ name: 'Netflix', category: catId });

预算金额

await api.setBudgetAmount('2026-01', categoryId, 30000);  // 预算 $300
await api.setBudgetCarryover('2026-01', categoryId, true); // 设置预算结转

规则

const rules = await api.getRules();
await api.createRule({
  stage: 'pre',
  conditionsOp: 'and',
  conditions: [{ field: 'payee', op: 'is', value: payeeId }],
  actions: [{ op: 'set', field: 'category', value: categoryId }],
});

计划任务

const schedules = await api.getSchedules();
await api.createSchedule({
  payee: payeeId,
  account: accountId,
  amount: -1500,
  date: { frequency: 'monthly', start: '2026-01-01', interval: 1, endMode: 'never' },
});

银行同步

await api.runBankSync({ accountId });  // GoCardless/SimpleFIN

同步与关闭

await api.sync();      // 推送/拉取更改到服务器
await api.shutdown();  // 操作完成后务必调用

ActualQL 查询

对于复杂查询,使用 ActualQL:

const { q, runQuery } = require('@actual-app/api');

// 按分类汇总本月支出
const { data } = await runQuery(
  q('transactions')
    .filter({
      date: [{ $gte: '2026-01-01' }, { $lte: '2026-01-31' }],
      amount: { $lt: 0 },
    })
    .groupBy('category.name')
    .select(['category.name', { total: { $sum: '$amount' } }])
);

// 搜索交易
const { data } = await runQuery(
  q('transactions')
    .filter({ 'payee.name': { $like: '%grocery%' } })
    .select(['date', 'amount', 'payee.name', 'category.name'])
    .orderBy({ date: 'desc' })
    .limit(20)
);

操作符: $eq, $lt, $lte, $gt, $gte, $ne, $oneof, $regex, $like, $notlike
拆分交易: .options({ splits: 'inline' | 'grouped' | 'all' })

辅助函数

// 按名称查找 ID
const acctId = await api.getIDByName('accounts', 'Checking');
const catId = await api.getIDByName('categories', 'Food');
const payeeId = await api.getIDByName('payees', 'Amazon');

// 列出预算
const budgets = await api.getBudgets();  // 本地 + 远程文件

转账

转账使用特殊的收款方。通过 transfer_acct 字段查找转账收款方:

const payees = await api.getPayees();
const transferPayee = payees.find(p => p.transfer_acct === targetAccountId);
await api.importTransactions(fromAccountId, [
  { date: '2026-01-15', amount: -10000, payee: transferPayee.id }
]);

拆分交易

await api.importTransactions(accountId, [{
  date: '2026-01-15',
  amount: -5000,
  payee_name: 'Costco',
  subtransactions: [
    { amount: -3000, category: groceryCatId },
    { amount: -2000, category: householdCatId },
  ]
}]);

批量导入(新预算)

适用于从其他应用迁移数据:

await api.runImport('My-New-Budget', async () => {
  for (const acct of myData.accounts) {
    const id = await api.createAccount(acct);
    await api.addTransactions(id, myData.transactions.filter(t => t.acctId === id));
  }
});

参考

完整 API 文档:https://actualbudget.org/docs/api/reference
ActualQL 文档:https://actualbudget.org/docs/api/actual-ql

3 次点击  ∙  0 人收藏  
登录后收藏  
目前尚无回复
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor