How we made a QR payment

Hello everyone! Today you are with Vladislav Kozulya, team lead of the Retail team, and I will tell you how to start paying by QR and not deny yourself anything. My team makes the product Kassa MoySklad, which is often used by our clients who have points of sale. It’s about how the development of tools for everyday work looks from the inside.

What is it all about

First, a little context. Usually, when you pay for purchases at the checkout, you have a choice: pay in cash or by card. Technically, there is another option between them – both that and that, but it is much less common. Or a bonus card, which is a separate system altogether. In short, cash or map.

Now a new method is added to them – payment by QR. Instead of pouring coins or pecking at the terminal with Applepe, you can scan the QR code and pay for the purchase through the bank’s application.

This raises a reasonable question: why bother with a camera on your phone, if the map is easier? It is profitable for the store. The trick is that for him the commission from the payment (and the store pays a commission to the bank from each purchase) will be lower. In addition, you can pay by QR without a terminal, that is, you can also save on the purchase of equipment. Therefore, the seller will offer you to pay by QR.

There are two types of codes: static and dynamic. The static code can be printed once and forgotten. Having scanned the code, the buyer must choose the amount of the transfer himself, so this scheme is more suitable for tips or donations. To pay for purchases, it is much more convenient to use dynamic codes that are generated on the bank’s side. This process can be automated through the cash register software, which we did.

The developer Ekaterina demonstrates how the function of printing a QR code on a receipt works
The developer Ekaterina demonstrates how the function of printing a QR code on a receipt works

Sberbank has its own system for this – Pay by QR, Tinkoff works using the Fast Payments System (FPS). Moreover, they are integrated with each other, that is, the buyer will not notice the difference. Both systems from our side are wrapped in a single API, so there is no difference for the client either.

Let’s analyze how payment by QR looks like under the hood from the point of view of the Checkout MoiSklad.

  1. The user of MyStore selects in the settings the bank with which he has a QR payment agreement. Now a new payment method will appear at his checkout.

  2. Cashier creates a sale – the cashier requests a QR code from the backend.

  3. The backend goes to the bank API, which the user selected from the first item. Gets a string containing data for generating a payment.

  4. The resulting string arrives at the checkout and is sewn into a QR code, which can be drawn on the UI or printed on a receipt – very convenient.

  5. Next, we interrogate the bank until it says that the payment has arrived or was canceled.

  6. You can print a fiscal receipt, hurray!

It seems like it sounds simple, which means it’s time to expect pitfalls.

Underwater rocks

Remember I mentioned that they usually pay in cash or by card? When we designed the base, we thought so too. Adding a new payment type means adding new fields to the database (we have PostgreSQL), and to the history of operations, one of the largest and most popular tables. On its basis, reports are formed, one of the key functions of MyStore. This time.

The second important point is that the service is stopped for updating only when there is simply no other way. This means that our decision should come to profit. This part deserves a separate article.

In addition to the usual payment, such exotic operations as prepayment, refund of payment and refund of prepayment are also possible. All of them must be correctly taken into account when working with QR. We simply did not begin to make a mixed QR + payment in cash or by card, otherwise we would have finally got lost in the rapidly becoming more complex logic.

MoySklad does not process payments, only records them. The cashier returns the money to your hands or to the card on his own, without the participation of cash register software. Paying via QR becomes a little more difficult: now the backend is responsible for canceling the transaction and refunding the payment. To do this, we save its ID after initialization.

In the API, both operations sit on the same endpoint (copied from Tinkov). Before making a payment, the transaction can be canceled, and when trying to pay, the buyer will see an error in the bank’s application. If the payment has already passed, a refund will be issued. In the event that something went wrong at the checkout, the store owner can always make a refund from his personal account in the bank.

Kassa MoiSklad is not a website, but a desktop application and a couple of mobile clients for iOS and Android. They can easily work even in the absence of communication for months: for this, a local base is raised there, that is, in fact, its own small backend. Accordingly, migration must be carried out both on the server and on the client. Breaking a local database means turning the checkout into a brick, or even worse: losing all data. A truly apocalyptic support scenario.

Moysklad Kassa architecture (simplified)
Moysklad Kassa architecture (simplified)

There is still a lot to tell about the desktop application, so let’s dwell on the problems that are relevant specifically for this task.


We launched SBP with Tinkov on October 1, and on December 1 – integration with Sberbank, Pay by QR. It’s almost February now, and we see a dozen daily payments. Customers use it, people pay for their purchases by QR. So, it was not in vain!

In the next installment, I’ll go into detail about how the pay-by-QR release hit the backend. Stay tuned!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *