Veröffentlicht 2026-05-01

Rules That Stick: How to Categorize Bank Transactions Automatically

A collage of photos with a couch, a car, a tree, etc.

You open your bank export. The same supermarket shows up three times, with three different names: REWE SAGT DANKE, REWE 123 KOELN, REWE//KOELN 4471. You sort them by hand. Next month the export arrives, and you sort them again. 😐

That is the problem rules solve. You tell Pinke once what something is. After that, it stays that way — this month, next month, next year.

Why consistency matters more than clever

A category is only useful if it means the same thing over time. If "groceries" means one thing in March and something else in October, you cannot compare the two months. You cannot spot a trend. Every chart lies a little.

So Pinke is rule-based on purpose. Rules are boring, and boring is the point. You can read a rule, understand it, and predict what it will do.

Two tools: merchants and rules

They sound similar. They do different jobs.

Merchants clean up names. REWE SAGT DANKE and REWE 123 KOELN both become one merchant: rewe. This is called an alias — a second name for the same shop.

Rules decide categories. They look at the text, the merchant, or the amount, and set the group, category and subcategory.

Merchants feed rules. Once the name is stable, a rule that says "when the merchant is rewe" is stable too.

You manage both on /rules and /merchants.

What happens when you press Analyze

When you analyze a file, Pinke runs four steps, in this order:

  1. Normalize — clean up the raw rows, build a searchable text blob, and match merchant aliases.
  2. Rules — your rules first, then the built-in system rules.
  3. ML fallback — only if no rule matched.
  4. Review — anything still unclear stays visible so you can deal with it.

The important part: your rules win. If you wrote a rule, nothing below it can overrule you.

The ML step ("machine learning" — a guess based on patterns, not a rule you wrote) is a safety net, not the main system. It only accepts its own guess when it is confident enough. Otherwise the row stays uncategorized on purpose, because a wrong category is worse than an empty one.

A real example

Input text: GRUNDSTEUER B STADT KOELN Rule that matched: housing.tax.grundsteuer_b Result: group fixed_costs, category housing, subcategory tax

And one where ML steps in, because no rule mentions this shop:

Input text: WOLT 8812 HELSINKI ML guess: group daily_life, category food, subcategory delivery

Walkthrough: your first rule in 6 steps

Say your gym, Nordlicht Fitness, shows up as NORDLICHT FIT GMBH LASTSCHRIFT and lands nowhere useful. It is 34,90 € every month. Let's fix it for good.

  1. Go to /rules. Under Your rules, click New rule.
  2. You will see a mode row: Exact match, Contains, Advanced. Pick Contains.
  3. In the text box, type nordlicht. Lowercase is fine — matching ignores upper and lower case.
  4. Below that is a sentence starting with Set. Fill in the blanks: group fun_lifestyle, category leisure, subcategory subscriptions. You can add tags like gym.
  5. Turn on Recurring? and pick Monthly. Now it counts as a subscription, not a surprise.
  6. Tick Apply this rule to all existing transactions in my history, then click Create rule.

That last checkbox is the one people miss. Without it, the rule only applies to future imports. With it, Pinke goes back and fixes the 34,90 € entries you already have.

Not sure a rule will do what you think? Use Test rule against history first. It shows you what would be hit before you commit to it.

Contains or regex?

Rules match text in two ways.

Contains is a plain search. aws finds AWS Emea Luxembourg. Use this almost always. It is easy to read and hard to break.

Regex (short for "regular expression" — a small pattern language for text) is for the awkward cases. It lives under the Advanced mode.

Pattern Matches When to use it
amzn.*mktp AMZN MKTP DE S1234 Something unknown sits between two words
paypal.*\d{4} PAYPAL REF 8812 You need digits (\d means "a digit")
(rewe\|aldi\|lidl) REWE SAGT DANKE Any one of several words

Rule of thumb: start with Contains. Reach for regex only when you have a reason you could say out loud.

When something is still unclear: Patterns

Some rows will not match anything. That is fine, and Pinke does not hide them.

On /ingest, after you analyze a file, click Patterns. Pinke groups similar rows together — by payee, merchant or description — and puts the uncategorized clusters first. You get suggestions like "these 7 rows look like the same thing."

From there you can create a rule right away and tick Apply to similar transactions, so the whole cluster is handled in one go.

If you ever wonder "why did this end up here?", open the row. Pinke records what matched: your rule, a system rule, or an ML guess.

The built-in rules

Pinke ships with a set of read-only system rules, grouped by category. They give you a decent starting point, so you are not staring at an empty page. You can browse them on /rules.

The structure is three levels deep:

group
  category
    subcategory

The groups are fixed_costs, daily_life, family, fun_lifestyle and finance_misc. So rent lands in fixed_costs > housing > rent, and a train ticket in daily_life > transport > public. Work costs are covered too, like finance_misc > work > cloud for a server bill.

There is also a dedicated set of securities rules for broker transactions. Those land under finance_misc > investments, split into securities_buy, securities_sell and dividends. They run before everything else on purpose. A share purchase named "Buy trade US0231351067 Amazon.com Inc" would otherwise hit the plain Amazon shopping rule, and a sale would look like a refund. They also key on the trade signal, never on the security name — so buying something from Amazon with your bank card is still shopping. And a share purchase is not counted as spending: the money became an asset, it did not leave your life.

One honest warning

Merchant changes are not retroactive. If you add an alias on /merchants, your already-analyzed rows do not change by themselves. Your charts, reports and exports keep showing the old result until you run analyze again.

Rules are different — that is exactly what the "apply to my history" checkbox is for. But for merchants, plan on a re-analyze.

What you get out of it

Once a handful of rules are in place, the boring monthly sorting mostly disappears. Your charts start comparing like with like. A jump in one category means something real happened, not that a shop renamed itself.

Start small. Pick the one transaction that annoys you most every month — rent, electricity, that gym — and write one rule for it. Use Contains. Tick the history box.

The goal is not a hundred rules. The goal is a set of categories you can still trust in a year. 🎯

Häufig gestellte Fragen

How do I categorize bank transactions automatically?

Write a rule that matches text in the transaction, then tell it which group, category and subcategory to set. Pinke applies that rule to every future import, and if you tick "apply to all existing transactions", it also fixes the entries you already have.

Why does the same shop show up under different names in my bank export?

Banks pass through whatever the payment terminal sent, so one supermarket can appear as REWE SAGT DANKE, REWE 123 KOELN and REWE//KOELN 4471. In Pinke you add these as aliases of one merchant, and the name becomes stable so rules can match it reliably.

Is transaction categorization rule-based or AI?

In Pinke it is rule-based first. Your own rules run before the built-in system rules, and a machine-learning guess only runs when no rule matched at all. If the guess is not confident enough, the transaction stays uncategorized on purpose — a wrong category is worse than an empty one.

Do new categorization rules apply to old transactions?

Only if you ask for it. When creating a rule, tick "Apply this rule to all existing transactions in my history" and Pinke goes back through your data. Merchant aliases are different: they are not retroactive, so you have to run analyze again.

Should I use contains or regex to match a transaction?

Use Contains almost always — it is a plain text search, easy to read and hard to break. Regex lives under the Advanced mode and is for awkward cases, like when something unknown sits between two words (amzn.*mktp) or you need to match digits.

Verwandel deine Kontoauszüge in Erkenntnisse.