blog·5 min read

Five ways to break your till through the MplusKASSA API

Writing to a till through the API works differently from reading. Five things we broke on our own test till, from vanished turnover groups to a link that is accepted but never stored.

Put our items and buttons into the till through the API and keep the
prices in line with what the accounting says.

Reading from a till is straightforward: you ask what has changed and you get it. Writing is a different game. A till is a device somebody will ring up a customer with in ten minutes, and an API that politely says "done" may have made that impossible in the meantime.

We worked this out on our own test till, a trial setup with demo data. Never on a client's till. This is what we broke there, and how you avoid it. There are no amounts, prices or margins here.

How we got to know the API in the first week is in the MplusKASSA API: what we learned.

1. Updating a list that gets replaced wholesale

The till's turnover groups can be updated with a single operation. It is named after "update", and that is misleading. It replaces the entire list with whatever you send.

Send three groups because you want to add three, and all the other groups are gone. In our case seven disappeared in one call. The result was not an error message but something much worse: ringing up a sale on the till failed afterwards. Items were attached to groups that no longer existed.

Recovering meant sending the full list again, including the groups we never meant to touch. That was only possible because we had read out the old list first and kept it.

The rule: read the list, add your change to what is already there, send everything back. And keep the answer from before the change, so rolling back is one call.

2. The same thing, but with the home screen

The till's button layout works in exactly the same way. The operation that saves a button group expects the whole group, with all main groups, tabs and buttons in it.

If you want to put one button in one spot, you first read out the entire layout for that branch and till, place your button in that structure and send the whole thing back. Forget half of it and that half is gone from the screen somebody works with.

This is the most painful of the five, because you do not see it in an error message. You see it when somebody is standing at the till and a tab is empty.

3. A product update that wants everything

Updating a product does not ask for the field you want to change, but for the whole product. You read it out, you change one thing, you send it all back.

There is a trap in that. The product data can contain a list of custom fields. If that list comes along empty or half filled, the till refuses the product. We had to strip that one empty field out of the data before the update went through.

The rule: sending back what you read is not enough. Strip the fields that come back empty before you offer them again.

4. Deleting does not exist, and groups come separately

Two things you expect that are not there.

There is no operation to delete a product. You set it to inactive. That makes sense for a till, because a deleted item would make last year's receipts unreadable, but it means a failed test round stays visibly in the list. So clean up your own trial items deliberately.

And when you create a product you can send item groups along. They are ignored. Without an error. The product is created, the group stays empty, and your item is nowhere on the screen. Putting a product in a group is a separate operation, afterwards.

This was the most instructive one. On an item you can supply a list of linked items, for instance to have a deposit counted automatically with a can.

Creating swallows that list. Updating does too. No error, no warning. But ask for the product afterwards and the list is not there. And more importantly: ring up a few of those items on the till, and the receipt shows no deposit. The till never stored the link.

We only found that out by actually ringing up a sale and looking at the receipt. A test that only checks whether the call succeeded would stay green here.

The rule: after every write action, check what the till kept by reading it back. And for anything that touches the receipt, check the receipt itself.

And then the till that does nothing at all

One more lesson from the same evening, on the side: after restoring the turnover groups, ringing up a sale kept failing, with a message about an unknown web address. The cause was a webhook configured on the till, with blocking events and an address that pointed nowhere. We wrote about that separately in a webhook that can block your till.

It belongs in this list because it has the same shape: the setting itself is valid, the consequences are somewhere else.

Common mistakes

Trusting an "update" without knowing whether it replaces. Read first, then send everything back. With lists that is the difference between a change and a clear-out.

Testing on a till somebody uses. Ask for a trial setup and make your mistakes there. A till that does not ring up sales is not an ordinary outage.

Only checking whether the call succeeded. Read back what was stored. An accepted field is not the same as a saved field.

Keeping no copy of the old state. Save what you are about to overwrite before you write. Recovery is then one step.

Letting one script do everything at once. Build it up in steps you can roll back separately, and look at the till's screen in between.

What a connected till can do is on connecting MplusKASSA. If you want something like this for your own shop or hospitality business, have a look at custom software.

MK
Maarten Keizer

Founder of Invoker. Over twenty years in hosting, system administration and web development; builds the Claude hosting himself and tests everything on our own servers first.

about maarten