Prerequisites

Before you start, make sure you have a few things in place. Nothing exotic — just the basics.

Getting your YNAB token

Head over to YNAB Developer Settings and click "New Personal Access Token". Give it a name you'll recognize (something like "payee splitter"), copy the token, and keep it somewhere safe. You'll need it every time you run the tool.

Heads up

YNAB only shows your token once when you create it. If you lose it, you'll need to create a new one.

Rate limits

The YNAB API has a rate limit per access token to prevent misuse. Normal usage of this tool is well within limits, but keep it in mind if you're running it very frequently. See the YNAB API docs for details.

Your first run

Let's get those payees cleaned up. We'll start with a dry run so you can see what the tool would do, without actually changing anything.

Recommended

Always use --dry-run the first time. It lets you preview the changes before committing them to your budget. Add --verbose for detailed output showing exactly which transactions will be split and how — really helpful to understand what the tool is doing. No surprises.

Try a dry run first

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --dry-run --verbose

Here's what happens when you run that command:

  1. The tool connects to the YNAB API using your token.
  2. It finds your last-used budget automatically (no need to specify one).
  3. It pulls your recent unapproved transactions from the last 30 days.
  4. For each transaction where the payee contains " - ", it splits it into a clean Payee and Memo.
  5. With --dry-run, it logs what it would change — but doesn't touch anything.

Happy with what you see? Run it for real by dropping the --dry-run flag:

Run it for real

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN

That's it. Your transactions are now clean. Payees are payees, memos are memos. The way it should have been from the start.

Targeting specific budgets and accounts

By default, the tool uses your last-used budget and processes all accounts. That's great for most people. But if you have multiple budgets or only want to clean up a specific account, you can be more precise.

Specifying a budget

Pass --budget-id to target a specific budget. You can find your budget ID in the YNAB web app URL — it's the long string after /budget/.

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --budget-id abc123-your-budget-id

Specifying an account

Similarly, use --account-id to only process a specific account within your budget:

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --budget-id BUDGET_ID \ --account-id ACCOUNT_ID

Controlling the lookback window

The tool looks back 30 days by default. Want to process older transactions? Use --days-back:

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --days-back 90

Using environment variables

Tired of typing long flags? Use environment variables instead. This is especially handy for automated setups (more on that in Section 5).

docker run --rm \ -e YNAB_TOKEN=YOUR_TOKEN \ -e YNAB_BUDGET_ID=BUDGET_ID \ -e YNAB_ACCOUNT_ID=ACCOUNT_ID \ ghcr.io/zzave/ynab-split-payee-and-memo

Approved vs unapproved transactions

By default, the tool only processes unapproved transactions. These are the ones that just came in from your bank and haven't been reviewed yet.

This is intentional: if you've already approved a transaction, you've probably looked at it and are happy with how it looks. The tool respects that and leaves it alone.

How it works

The tool also skips any transaction where you've manually changed the payee name (it checks whether payee_name still matches import_payee_name). Transfers (payees starting with "Transfer : ") are always skipped too.

Want to go back and clean up older, already-approved transactions? Use the --all flag:

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --all

This processes every eligible transaction in the lookback window, regardless of approval status. Pair it with --dry-run and a larger --days-back to preview the full blast radius before committing:

docker run --rm \ ghcr.io/zzave/ynab-split-payee-and-memo \ --token YOUR_TOKEN \ --all --days-back 365 --dry-run

Automate it

The real magic is running this automatically. Set up a cron job and never think about messy payees again. Every morning, your transactions are clean before you even open YNAB.

Quick cron setup

Create a small shell script that runs the Docker container with your token. Use environment variables to keep things tidy:

~/scripts/run-ynab-splitter.sh

#!/bin/bash DOCKER=/usr/local/bin/docker YNAB_TOKEN=YOUR_TOKEN $DOCKER run --rm \ -e YNAB_TOKEN=$YNAB_TOKEN \ ghcr.io/zzave/ynab-split-payee-and-memo \ --days-back 7

Make it executable and add it to your crontab:

Make the script executable

chmod +x ~/scripts/run-ynab-splitter.sh

Add to crontab (crontab -e)

# Run every day at 8 AM 0 8 * * * ~/scripts/run-ynab-splitter.sh >> ~/ynab-splitter.log 2>&1
Tip

Use --days-back 7 for cron jobs instead of the default 30. Since you're running it regularly, a week's lookback is plenty — and it's faster.

Running in the cloud?

Skip the local cron setup and run this as a managed job instead. See the Scaleway Serverless Jobs guide for a hands-off setup that runs whether your laptop is on or not.

For detailed platform-specific instructions (including macOS-specific tips and how to disable the job later), see the full cron setup guide in the README.

CLI reference

Every flag and option at a glance. All flags can also be set via the corresponding environment variable where noted.

-t, --token Required
Your YNAB Personal Access Token. This is how the tool authenticates with the YNAB API.
Env: YNAB_TOKEN
-b, --budget-id
Target a specific YNAB budget. If omitted, the tool uses your last-used budget.
Env: YNAB_BUDGET_ID
--budget-ids
Comma-separated list of budget IDs to process multiple budgets in one run. Cannot be used with --budget-id.
Env: YNAB_BUDGET_IDS
-a, --account-id
Only process transactions from a specific account. If omitted, all accounts are processed.
Env: YNAB_ACCOUNT_ID
-d, --days-back Default: 30
How many days of transaction history to look back. Increase for a one-time bulk cleanup; decrease for faster cron runs.
--dry-run
Preview mode. Logs what would be changed without actually updating any transactions. Always a good idea for your first run.
--only-unapproved Default: true
Only process unapproved (newly imported) transactions. This is the default behavior.
--all
Process all eligible transactions regardless of approval status. Opposite of --only-unapproved.
-v, --verbose
Enable debug logging for more detailed output. Useful for troubleshooting.