Taking new projectsWarsaw and Poznań · local timeWe reply within one business day5.0 on Google · 25 reviews
fessburnPLStart a project

Translating technical error codes into actionable user-facing copy

Gideon Awolesi ·

Right now, if you send an invoice from a lot of finance apps in Poland and KSeF rejects it, you'll see the error the way the system returned it: a status code and a technical message written for developers. That isn't human readable, and it isn't good UX copy. The person looking at it is usually a sole trader or a bookkeeper, and all they want to know is what went wrong and what they need to do to get the invoice through.

01Why this screen matters more in 2026

Since 1 February 2026, companies with a turnover above PLN 200 million have issued their invoices through KSeF, and every other VAT payer joined on 1 April 2026. The smallest businesses join on 1 January 2027. So a rejected invoice isn't an edge case for a finance app in Poland anymore. It's a screen a lot of people will see, often on their phone, and often for the first time.

A lot of teams spend their design time on the happy path, where the invoice goes through and everyone's happy. The rejected invoice gets whatever the API sends back. That's the screen where people decide if they can rely on your app, so it deserves the same design time as the happy path.

02What we ran into with InvoiceRate

InvoiceRate is one of our own apps. Polish sole traders use it to send invoices, pull their purchase invoices from KSeF, and get their records ready for their accountant, all from their phone, and 3,000+ people use it.

The app is only connected to KSeF through an API, so every rejection reaches us as a technical response from a government system we don't control. We had to design the screens for those rejections ourselves. These are problems you don't have when you're only designing the happy path in a Figma file, and they're where this approach comes from.

03How to translate an error code into copy people can act on

Start with the list of errors the API can return. Then group the ones that mean the same thing to the user, and write one message for each group. For each message, go through these steps:

  1. Say what happened to their invoice, in their words. For example, KSeF didn't accept the invoice, so it hasn't been issued yet.
  2. Say what they need to do next, and point them to the field or the setting they need to change.
  3. Let them know what's safe. If their draft is saved, say so, so they don't start again from scratch.
  4. Put the technical details below the message, for the accountant or the support team who want to check them.

It's also important that you separate the errors the user can fix from the ones they can't. If KSeF itself is unavailable, there's nothing for the user to change. In that case, let them know the problem is on KSeF's side, and if your app sends the invoice again automatically, say that too.

04What this looks like on the screen

Before

Validation error: document structure invalid

After

KSeF didn't accept this invoice because the buyer's NIP is missing. Add the buyer's NIP and send it again. Your draft is saved.

This is an illustration of the pattern, not a real KSeF message. The technical error still sits below the new copy, for anyone who wants to check it.

The new version lets the person know what went wrong and how to fix it. It also lets them know their draft is saved. The error code is still there, for the people who are more technically inclined and want to check it.

05If you're building on KSeF

If your product talks to KSeF or another system you don't control, it's important that you go through the error states screen by screen with real users. Send us the flow you're worried about, and we'll tell you how we'd handle it.