diff --git a/packages/api/.gitignore b/packages/api/.gitignore
index 1682676f0b6695791c4e95fd8e17cb33fb3906ca..25df81978441e97c5d2bf32d382e53512c39f809 100644
--- a/packages/api/.gitignore
+++ b/packages/api/.gitignore
@@ -2,3 +2,4 @@ app/bundle.api.js*
 app/stats.json
 migrations
 default-db.sqlite
+mocks/budgets/**/*
diff --git a/packages/api/__snapshots__/methods.test.ts.snap b/packages/api/__snapshots__/methods.test.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..806d2194337f0c529bd63f7e7966ed959243e0d4
--- /dev/null
+++ b/packages/api/__snapshots__/methods.test.ts.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`API setup and teardown successfully loads budget 1`] = `
+Array [
+  "2016-10",
+  "2016-11",
+  "2016-12",
+  "2017-01",
+  "2017-02",
+  "2017-03",
+  "2017-04",
+  "2017-05",
+  "2017-06",
+  "2017-07",
+  "2017-08",
+  "2017-09",
+  "2017-10",
+  "2017-11",
+  "2017-12",
+]
+`;
diff --git a/packages/api/index.js b/packages/api/index.js
index aebc7c061d44a81b6794c8e2629c0b6e8032b1f0..4473e540c86a0ef82967dd3e383b485d94ee297d 100644
--- a/packages/api/index.js
+++ b/packages/api/index.js
@@ -1,5 +1,3 @@
-/* eslint-disable import/no-unused-modules */
-
 // eslint-disable-next-line import/extensions
 import * as bundle from './app/bundle.api.js';
 import * as injected from './injected';
diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d98fde77d2434e64499f59487aa54a6ee6a5bf8
--- /dev/null
+++ b/packages/api/jest.config.js
@@ -0,0 +1,24 @@
+module.exports = {
+  moduleFileExtensions: [
+    'testing.js',
+    'testing.ts',
+    'api.js',
+    'api.ts',
+    'api.tsx',
+    'electron.js',
+    'electron.ts',
+    'mjs',
+    'js',
+    'ts',
+    'tsx',
+    'json',
+  ],
+  testEnvironment: 'node',
+  testPathIgnorePatterns: ['/node_modules/'],
+  watchPathIgnorePatterns: ['<rootDir>/mocks/budgets/'],
+  setupFilesAfterEnv: ['<rootDir>/../loot-core/src/mocks/setup.ts'],
+  transformIgnorePatterns: ['/node_modules/'],
+  transform: {
+    '^.+\\.(t|j)sx?$': '@swc/jest',
+  },
+};
diff --git a/packages/api/methods.test.ts b/packages/api/methods.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5284966b98de0874683f20ca9a493c77f248db7
--- /dev/null
+++ b/packages/api/methods.test.ts
@@ -0,0 +1,147 @@
+import * as fs from 'fs/promises';
+import * as path from 'path';
+
+import * as api from './index';
+
+const budgetName = 'test-budget';
+
+beforeEach(async () => {
+  // we need real datetime if we are going to mix new timestamps with our mock data
+  global.restoreDateNow();
+
+  const budgetPath = path.join(__dirname, '/mocks/budgets/', budgetName);
+  await fs.rm(budgetPath, { force: true, recursive: true });
+
+  await createTestBudget('default-budget-template', budgetName);
+  await api.init({
+    dataDir: path.join(__dirname, '/mocks/budgets/'),
+  });
+});
+
+afterEach(async () => {
+  global.currentMonth = null;
+  await api.shutdown();
+});
+
+async function createTestBudget(templateName: string, name: string) {
+  const templatePath = path.join(
+    __dirname,
+    '/../loot-core/src/mocks/files',
+    templateName,
+  );
+  const budgetPath = path.join(__dirname, '/mocks/budgets/', name);
+
+  await fs.mkdir(budgetPath);
+  await fs.copyFile(
+    path.join(templatePath, 'metadata.json'),
+    path.join(budgetPath, 'metadata.json'),
+  );
+  await fs.copyFile(
+    path.join(templatePath, 'db.sqlite'),
+    path.join(budgetPath, 'db.sqlite'),
+  );
+}
+
+describe('API setup and teardown', () => {
+  // apis: loadBudget, getBudgetMonths
+  test('successfully loads budget', async () => {
+    await expect(api.loadBudget(budgetName)).resolves.toBeUndefined();
+
+    await expect(api.getBudgetMonths()).resolves.toMatchSnapshot();
+  });
+});
+
+describe('API CRUD operations', () => {
+  beforeEach(async () => {
+    // load test budget
+    await api.loadBudget(budgetName);
+  });
+
+  // apis: setBudgetAmount, setBudgetCarryover, getBudgetMonth
+  test('Budgets: successfully update budgets', async () => {
+    const month = '2023-10';
+    global.currentMonth = month;
+
+    // create some new categories to test with
+    const groupId = await api.createCategoryGroup({
+      name: 'tests',
+    });
+    const categoryId = await api.createCategory({
+      name: 'test-budget',
+      group_id: groupId,
+    });
+
+    await api.setBudgetAmount(month, categoryId, 100);
+    await api.setBudgetCarryover(month, categoryId, true);
+
+    const budgetMonth = await api.getBudgetMonth(month);
+    expect(budgetMonth.categoryGroups).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          id: groupId,
+          categories: expect.arrayContaining([
+            expect.objectContaining({
+              id: categoryId,
+              budgeted: 100,
+              carryover: true,
+            }),
+          ]),
+        }),
+      ]),
+    );
+  });
+
+  //apis: createAccount, getAccounts, updateAccount, closeAccount, deleteAccount, reopenAccount
+  test('Accounts: successfully complete account operators', async () => {
+    const accountId1 = await api.createAccount(
+      { name: 'test-account1', offbudget: true },
+      1000,
+    );
+    const accountId2 = await api.createAccount({ name: 'test-account2' }, 0);
+    let accounts = await api.getAccounts();
+
+    // accounts successfully created
+    expect(accounts).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          id: accountId1,
+          name: 'test-account1',
+          offbudget: true,
+        }),
+        expect.objectContaining({ id: accountId2, name: 'test-account2' }),
+      ]),
+    );
+
+    await api.updateAccount(accountId1, { offbudget: false });
+    await api.closeAccount(accountId1, accountId2, null);
+    await api.deleteAccount(accountId2);
+
+    // accounts successfully updated, and one of them deleted
+    accounts = await api.getAccounts();
+    expect(accounts).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          id: accountId1,
+          name: 'test-account1',
+          closed: true,
+          offbudget: false,
+        }),
+        expect.not.objectContaining({ id: accountId2 }),
+      ]),
+    );
+
+    await api.reopenAccount(accountId1);
+
+    // the non-deleted account is reopened
+    accounts = await api.getAccounts();
+    expect(accounts).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          id: accountId1,
+          name: 'test-account1',
+          closed: false,
+        }),
+      ]),
+    );
+  });
+});
diff --git a/packages/api/mocks/budgets/.gitkeep b/packages/api/mocks/budgets/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/packages/api/package.json b/packages/api/package.json
index 0ef8b7de68ea5a93bb5952bc1b61f992a4302995..e3c71255ff59f35a7c6da3de0660424d9fca8e35 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -16,7 +16,8 @@
     "build:node": "tsc --p tsconfig.dist.json",
     "build:migrations": "cp migrations/*.sql dist/migrations",
     "build:default-db": "cp default-db.sqlite dist/",
-    "build": "rm -rf dist && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db"
+    "build": "rm -rf dist && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db",
+    "test": "yarn run build:app && jest -c jest.config.js"
   },
   "dependencies": {
     "better-sqlite3": "^9.1.1",
@@ -25,7 +26,11 @@
     "uuid": "^9.0.0"
   },
   "devDependencies": {
+    "@swc/core": "^1.3.82",
+    "@swc/jest": "^0.2.29",
+    "@types/jest": "^27.5.0",
     "@types/uuid": "^9.0.2",
+    "jest": "^27.0.0",
     "typescript": "^5.0.2"
   }
 }
diff --git a/upcoming-release-notes/1991.md b/upcoming-release-notes/1991.md
new file mode 100644
index 0000000000000000000000000000000000000000..5fa4b94bdddd2d4537fa6f0ffd5285dd729a3d9b
--- /dev/null
+++ b/upcoming-release-notes/1991.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [twk3]
+---
+
+Add some initial api tests for budgets and accounts
diff --git a/yarn.lock b/yarn.lock
index 1dd1f7c5915e2898726d09dfc7fca8f5baf05c66..2251b1091e102e77f3dc75263b8010f40614d082 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -23,9 +23,13 @@ __metadata:
   version: 0.0.0-use.local
   resolution: "@actual-app/api@workspace:packages/api"
   dependencies:
+    "@swc/core": "npm:^1.3.82"
+    "@swc/jest": "npm:^0.2.29"
+    "@types/jest": "npm:^27.5.0"
     "@types/uuid": "npm:^9.0.2"
     better-sqlite3: "npm:^9.1.1"
     compare-versions: "npm:^6.1.0"
+    jest: "npm:^27.0.0"
     node-fetch: "npm:^3.3.2"
     typescript: "npm:^5.0.2"
     uuid: "npm:^9.0.0"