KSeF

Auto-assign KSeF invoices to projects — step by step

KSeFMakeClaude

Czytaj po polsku: wersja polska

Now that KSeF delivers every supplier and subcontractor invoice in one structured format, the most valuable first automation in a construction firm is also the most boring: getting each invoice onto the right project, without anyone re-typing it. Here’s how to build it.

What you’ll end up with

  • Every inbound KSeF invoice lands in a sheet/board, already tagged to a project.
  • ~80% are matched automatically by rules.
  • The ~20% that aren’t go into an exceptions queue for a human to resolve in seconds.

You don’t need a developer. Make (or n8n) plus one AI step is enough.

Step 1 — Get the invoices out of KSeF and into one place

Pull inbound invoices via your accounting tool’s KSeF export or the API into a single table (Google Sheet, Airtable, or a Make data store). Capture the fields KSeF already gives you: seller NIP, seller name, line-item text, gross amount, issue date, invoice number.

Don’t skip this. A clean, append-only list of inbound invoices is the foundation — automate nothing until it’s reliable.

Step 2 — Write your matching rules first (on paper)

Before any automation, write down how you decide which project an invoice belongs to. It’s usually one of:

  • Seller NIP → project (this concrete supplier only delivers to the Mokotów site this quarter).
  • Keyword in line items → project (an address, a project code, a material tied to one build).
  • Amount threshold → review (anything over X always gets eyes on it).

If you can’t write the rule, AI can’t apply it. Most firms find 5–10 rules cover the bulk.

Step 3 — Build the rule layer in Make

Create a scenario triggered on “new row” in your invoice table:

  1. A Router with one path per high-confidence rule (NIP match, project-code match).
  2. Each path sets a project field and a confidence: high flag.
  3. A fallback path leaves project empty with confidence: low.

This alone will auto-tag every invoice from your regular suppliers.

Step 4 — Add one AI step for the messy ones

For the fallback path, add an AI module (Claude/OpenAI) with a tight prompt:

You match construction invoices to projects.
Active projects: {{list of projects + their addresses/codes}}
Invoice: seller {{seller}}, items "{{line_items}}", amount {{amount}}.
Return JSON: { "project": "<name or 'unknown'>", "reason": "<short>" }.
If unsure, return "unknown".

Crucially: tell it to return unknown when unsure. A confident wrong guess is worse than an honest “I don’t know.”

Step 5 — Route the exceptions to a human

  • confidence: high (rules) or AI returned a project → write the tag, done.
  • AI returned unknown or low confidence → push to an exceptions queue (a filtered view, a Slack message, whatever your PM already checks).

The PM now reviews a handful of invoices a week instead of sorting all of them. Over time, the patterns they keep resolving the same way become new Step-3 rules — and the queue shrinks.

Watch-outs

  • Duplicates: dedupe on invoice number + NIP before tagging.
  • Don’t auto-approve payment off this — it tags and routes; a human still approves money.
  • Log the AI’s reason — it’s how you debug and turn judgments into rules.

Start with rules, add the one AI step for the long tail, and keep a human on the exceptions. That’s the whole pattern — and it’s the same shape for quoting, follow-ups, and document routing.