> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corsair.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# YNAB plugin

> Budgeting with YNAB - read budgets, accounts, categories, payees and months, assign money to categories, and create, update and delete transactions and scheduled transactions.

Use **YNAB** through Corsair: one client, typed API calls.

This plugin supports personal use of your own YNAB account only. Never collect another person's personal access token. YNAB requires OAuth for access to other users' accounts, and this plugin does not implement OAuth. The shared tenant-connect examples below do not apply to this plugin. Pass your own token with `ynab({ key: process.env.YNAB_API_KEY! })`.

Create a personal access token in YNAB under **Account Settings → Developer Settings → New Token**. It goes in `Authorization: Bearer` against `https://api.ynab.com/v1`.

* **Amounts are milliunits, not currency.** Every amount is the currency value times 1,000, so $12.34 is `12340` and $1,234.56 is `1234560`. An amount is a whole number of milliunits, so a fractional value is rejected before the request rather than rounded. Reading a milliunit as a decimal is the most common mistake with this API.
* **Outflows are negative.** A \$12.34 purchase is `-12340`, and an inflow is positive. The sign carries the direction; there is no separate field.
* **A category assignment replaces, it does not add.** `categories.update` sets the month's budgeted amount to exactly the value given, so sending `50000` makes the month $50 — it does not add $50. Sending `0` clears it.
* **Dates are `yyyy-MM-dd`.** No time and no zone. A month is addressed by its first day, so `2024-06-01` is June.
* **Everything is wrapped in `data`.** Every response is `{ data: … }`, and list endpoints add `server_knowledge` — a counter you can pass back as `last_knowledge_of_server` to receive only what changed since. That is worth using, because a full budget is very large.
* **`budgets.get` returns the whole budget.** Every account, category, payee, month and transaction in one answer, which is huge for a real budget. `last-used` reaches the most recently opened one without listing first.
* **Transactions can be created 500 at a time.** The batch is validated together rather than one call each, and an `import_id` on each makes a repeat safe: a transaction whose import\_id already exists on the same account is skipped, not updated, and is reported in `duplicate_import_ids`. Use `transactions.update` for corrections.
* **A split transaction has a null parent category.** When `subtransactions` is non-empty, the parent's `category_id` and `category_name` are null and the amounts live on the splits.
* **Check the error name on a 403.** `subscription_lapsed` requires renewal, `trial_expired` requires a subscription, `unauthorized_scope` requires write permission, `data_limit_reached` means the request exceeds an API data limit, and `email_unconfirmed` requires email confirmation. A 401 indicates a missing, invalid or revoked token.
* **A malformed delta request is rejected whole.** Nothing is partly applied, which is why a 400 is never retried.
* **Memo and payee names are personal.** A memo can name a merchant and a payee can name an employer, so the plugin logs ids, amounts and cleared state rather than text.

**What you get:**

* 24 typed API operations

## Setup

**1. Install**

```bash npm theme={null}
npm install corsair @corsair-dev/ynab better-sqlite3
npm install --save-dev @types/better-sqlite3
```

```bash yarn theme={null}
yarn add corsair @corsair-dev/ynab better-sqlite3
yarn add --dev @types/better-sqlite3
```

```bash pnpm theme={null}
pnpm install corsair @corsair-dev/ynab better-sqlite3
pnpm install --save-dev @types/better-sqlite3
```

```bash bun theme={null}
bun add corsair @corsair-dev/ynab better-sqlite3
bun add --dev @types/better-sqlite3
```

**2. Add the plugin**

```ts corsair.ts theme={null}
import Database from 'better-sqlite3';
import { createCorsair } from 'corsair';
import { ynab } from '@corsair-dev/ynab';

export const corsair = createCorsair({
	plugins: [
		ynab(),
	],
	database: new Database('corsair.db'),
	kek: process.env.CORSAIR_KEK!,
	multiTenancy: true,
	hub: {
		projectApiKey: process.env.CORSAIR_API_KEY!,
		signingSecret: process.env.CORSAIR_SIGNING_SECRET!,
	},
});
```

With `multiTenancy: true`, scope calls with `corsair.withTenant(id)`. See [Quick start](https://docs.corsair.dev/quick-start.md) for KEK + Hub keys, and [Multi-tenancy](https://docs.corsair.dev/concepts/multi-tenancy.md) for account isolation.

**3. Choose authentication**

> [tab] API Key (Recommended)
>
> No setup required yet. When you make your first request as a tenant, Corsair prompts for the API key.
>
> ```ts theme={null}
> ynab()
> ```
>
> More: [API Key](https://docs.corsair.dev/concepts/api-key)

**4. Connect a tenant**

Mint a connect link and send the tenant to it. Hub hosts the page and delivers the result to your app — see [Connect / OAuth](https://docs.corsair.dev/management/connect).

```ts theme={null}
const { connectUrl } = await corsair.manage.connect.createLink({
	plugin: 'ynab',
	tenantId: 'acme',
});
// redirect the user's browser to connectUrl
```

## Example API calls

**List the accounts in a budget**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.ynab.api.accounts.list({ budgetId: 'last-used' });
```

**Record a purchase**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.ynab.api.transactions.create({
	budgetId: 'last-used',
	transactions: [{ account_id: 'acc00000-0000-0000-0000-000000000001', date: '2024-06-01', amount: -123450 }],
});
```

See the full list on the [API](https://docs.corsair.dev/plugins/ynab/api.md) page.

## What's next

> [card] [API reference](https://docs.corsair.dev/plugins/ynab/api.md)
>
> Every `ynab.api.*` operation with input and output types.

> [card] [Connect / OAuth](https://docs.corsair.dev/management/connect)
>
> createLink, Hub delivery, and tenant connect flows.

> [card] [Use with agents](https://docs.corsair.dev/mcp-adapters/mcp-adapters)
>
> Expose this plugin's operations as MCP tools.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.