Skip to content

brysonreece/monarch-api

Repository files navigation

monarch-api

A TypeScript SDK for the Monarch API.

Installation

npm install monarch-api

Quick Start

import { MonarchClient } from 'monarch-api';

const client = new MonarchClient();

await client.login({
  email: 'you@example.com',
  password: 'your-password',
});

const accounts = await client.accounts.list();
console.log(accounts);

Authentication

Email & Password

const client = new MonarchClient();

await client.login({
  email: 'you@example.com',
  password: 'your-password',
});

Multi-Factor Authentication

If your account has MFA enabled, login will throw a RequireMFAError. Handle it by prompting the user for their code:

import { MonarchClient, RequireMFAError } from 'monarch-api';

const client = new MonarchClient();

try {
  await client.login({ email, password });
} catch (err) {
  if (err instanceof RequireMFAError) {
    await client.multiFactorAuthenticate({
      email,
      password,
      code: '123456', // 6-digit TOTP code
    });
  }
}

If you have access to your TOTP secret key, you can pass it directly to login and the SDK will handle MFA automatically:

await client.login({
  email,
  password,
  mfaSecretKey: 'YOUR_TOTP_SECRET',
});

Reusing a Token

To avoid re-authenticating on every run, you can initialize the client with an existing token:

const client = new MonarchClient({ token: 'your-token' });

Persisting Sessions

For scripts and automations, we recommend saving your session token to a file (e.g. ~/.monarch-session.json) and reusing it across runs. This avoids logging in on every execution.

import { MonarchClient, RequireMFAError } from 'monarch-api';
import { readFileSync, writeFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';

const SESSION_FILE = join(homedir(), '.monarch-session.json');

function loadSession(): { token: string } | null {
  try {
    return JSON.parse(readFileSync(SESSION_FILE, 'utf-8'));
  } catch {
    return null;
  }
}

function saveSession(token: string) {
  writeFileSync(SESSION_FILE, JSON.stringify({ token }), { mode: 0o600 });
}

const session = loadSession();
const client = new MonarchClient(session ?? undefined);

if (!session) {
  try {
    await client.login({ email, password });
  } catch (err) {
    if (err instanceof RequireMFAError) {
      await client.multiFactorAuthenticate({ email, password, code: '123456' });
    } else {
      throw err;
    }
  }

  saveSession(client.token!);
}

// client is ready to use
const accounts = await client.accounts.list();

Note: ~/.monarch-session.json contains a sensitive auth token. The example above sets file permissions to 0o600 (owner read/write only). Add it to your .gitignore if the file is inside a project directory.

API Reference

client.accounts

// List all connected accounts
const accounts = await client.accounts.list();

// Create a manual account
const { id } = await client.accounts.create({
  name: 'Savings Account',
  type: 'savings',
  balance: 5000,
  currency: 'USD',
});

// Update an account
const updated = await client.accounts.update(accountId, {
  displayName: 'Emergency Fund',
  includeInNetWorth: true,
});

// Delete an account
await client.accounts.delete(accountId);

// Get investment holdings
const holdings = await client.accounts.getHoldings(accountId);

// Get balance history
const history = await client.accounts.getHistory(accountId, {
  startDate: '2025-01-01',
  endDate: '2025-12-31',
});

// Refresh account data from institution
await client.accounts.refresh([accountId]);

// Refresh and wait for sync to complete
await client.accounts.refreshAndWait([accountId]);

client.transactions

// List transactions
const transactions = await client.transactions.list({
  startDate: '2025-01-01',
  endDate: '2025-01-31',
  limit: 100,
});

// Get a single transaction
const tx = await client.transactions.get(transactionId);

// Create a manual transaction
const { id } = await client.transactions.create({
  accountId,
  date: '2025-01-15',
  amount: -42.50,
  merchantName: 'Coffee Shop',
  categoryId,
});

// Update a transaction
await client.transactions.update(transactionId, {
  notes: 'Team lunch',
  categoryId: 'food-and-dining',
});

// Delete a transaction
await client.transactions.delete(transactionId);

// Split a transaction
await client.transactions.updateSplits(transactionId, [
  { amount: 25.00, categoryId: 'groceries' },
  { amount: 17.50, categoryId: 'household' },
]);

// Categories
const categories = await client.transactions.categories.list();
const groups = await client.transactions.categories.groups();
await client.transactions.categories.create({ name: 'Pet Care', groupId });

// Tags
const tags = await client.transactions.tags.list();
await client.transactions.tags.create('Reimbursable', '#FF5733');
await client.transactions.tags.set(transactionId, [tagId]);

client.budgets

// Get budget data for a month
const { budgetData, categoryGroups } = await client.budgets.list({
  startDate: '2025-01-01',
  endDate: '2025-01-31',
});

// Set a budget amount
await client.budgets.set(categoryId, 500, {
  startDate: '2025-01-01',
  endDate: '2025-01-31',
  rolloverEnabled: true,
});

client.cashflow

// Get full cashflow breakdown
const cashflow = await client.cashflow.get({
  startDate: '2025-01-01',
  endDate: '2025-01-31',
});

// Get cashflow summary
const summary = await client.cashflow.getSummary({
  startDate: '2025-01-01',
  endDate: '2025-01-31',
});
// { income, expenses, savings, savingsRate }

client.recurring

// List recurring transactions
const recurring = await client.recurring.list({
  startDate: '2025-01-01',
  endDate: '2025-01-31',
});

// Update a recurring transaction
await client.recurring.update(merchantId, {
  frequency: 'monthly',
  amount: 14.99,
});

client.institutions

// List connected institutions
const institutions = await client.institutions.list();

client.creditHistory

// Get credit score history
const scores = await client.creditHistory.get();

client.subscription

// Get subscription details
const subscription = await client.subscription.get();

Raw GraphQL Responses

Every method that returns processed data also accepts a { raw: true } option to get the unprocessed GraphQL response:

const raw = await client.accounts.list({ raw: true });
const raw = await client.institutions.list({ raw: true });
const raw = await client.creditHistory.get({ raw: true });

Error Handling

import {
  MonarchError,
  LoginFailedError,
  RequireMFAError,
  RequestFailedError,
} from 'monarch-api';

try {
  await client.login({ email, password });
} catch (err) {
  if (err instanceof LoginFailedError) {
    // Invalid credentials
  } else if (err instanceof RequireMFAError) {
    // MFA required
  } else if (err instanceof RequestFailedError) {
    // API request failed
  } else if (err instanceof MonarchError) {
    // Other SDK error
  }
}

TypeScript

This package is written in TypeScript and ships with full type definitions. All request options and response shapes are typed.

import type {
  Account,
  Transaction,
  TransactionCategory,
  Budget,
  CashflowSummary,
  RecurringTransaction,
} from 'monarch-api';

Development TUI

This repo also includes an interactive terminal UI for exploring the SDK against a live Monarch account. It's useful for development and serves as a reference example of a client application built with monarch-api.

npm run dev:tui

The TUI handles authentication automatically — it will prompt for credentials on first run and cache the session token to ~/.monarch-session.json for subsequent runs. You can also pre-fill credentials via environment variables:

MONARCH_EMAIL=you@example.com \
MONARCH_PASSWORD=your-password \
MONARCH_MFA_SECRET=YOUR_TOTP_SECRET \
npm run dev:tui

Modules

The TUI is organized into modules, selectable from the left sidebar:

Module Description
Welcome Verifies your session token, shows masked token and account count
Accounts Lists all connected accounts with type and balance, plus total net worth
Transactions Displays the last 30 days of transactions with date, merchant, category, and amount

Navigation

Key Action
/ or j / k Navigate the module list
Enter Launch the selected module
Tab Toggle focus between sidebar and output pane
/ Scroll output one line
PageUp / PageDown Scroll output one page
t / b Jump to top / bottom of output
f Toggle follow mode (auto-scroll as output arrives)
q Quit

Adding Modules

Modules are auto-discovered from tui/modules/*.ts. Each module exports a name string and a run(context) function:

import type { Module } from '../lib/types.js';

export const name = 'My Module';

export const run: Module = async ({ client, display, signal }) => {
  display.header('My Module');
  const accounts = await client.accounts.list();
  display.table(accounts, ['name', 'currentBalance']);
};

License

Distributed under the MIT License, see LICENSE.md for details.

About

An expressive TypeScript SDK for interacting with the Monarch API

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors