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.updatesets the month’s budgeted amount to exactly the value given, so sending50000makes the month $50 — it does not add $50. Sending0clears it. - Dates are
yyyy-MM-dd. No time and no zone. A month is addressed by its first day, so2024-06-01is June. - Everything is wrapped in
data. Every response is{ data: … }, and list endpoints addserver_knowledge— a counter you can pass back aslast_knowledge_of_serverto receive only what changed since. That is worth using, because a full budget is very large. budgets.getreturns the whole budget. Every account, category, payee, month and transaction in one answer, which is huge for a real budget.last-usedreaches 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_idon each makes a repeat safe: a transaction whose import_id already exists on the same account is skipped, not updated, and is reported induplicate_import_ids. Usetransactions.updatefor corrections. - A split transaction has a null parent category. When
subtransactionsis non-empty, the parent’scategory_idandcategory_nameare null and the amounts live on the splits. - Check the error name on a 403.
subscription_lapsedrequires renewal,trial_expiredrequires a subscription,unauthorized_scoperequires write permission,data_limit_reachedmeans the request exceeds an API data limit, andemail_unconfirmedrequires 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.
- 24 typed API operations
Setup
1
Install
2
Add the plugin
corsair.ts
multiTenancy: true, scope calls with corsair.withTenant(id). See Quick start for KEK + Hub keys, and Multi-tenancy for account isolation.3
Choose authentication
- API Key (Recommended)
No setup required yet. When you make your first request as a tenant, Corsair prompts for the API key.More: 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.
Example API calls
List the accounts in a budgetWhat’s next
API reference
Every
ynab.api.* operation with input and output types.Connect / OAuth
createLink, Hub delivery, and tenant connect flows.
Use with agents
Expose this plugin’s operations as MCP tools.