Choosing a thermal printer for your counter and kitchen
USB, network or Bluetooth? What to look for when buying an 80mm receipt printer for a restaurant.
Engineering
Why Snapitto uses a single running order number with a brand prefix, and how it survives offline tills and concurrent sales.
Order numbers look like the simplest part of a POS. You add one to the last number. In practice, the moment you have more than one till, or an internet connection that comes and goes, it gets interesting. This post explains the choice we made and the reasoning.
Snapitto uses one running order number per business, shared by all of its outlets and never reset at midnight. The number is shown with a short prefix made from the business's initials, so Love Pizza Cafe sees LPC12, then LPC13, and so on.
Earlier, numbers were allocated per location per day. That is the classic approach: "order 1" every morning. It has real drawbacks.
A single running number removes the ambiguity. A number means exactly one order, anywhere in the business, forever.
The initials prefix is for people, not for the database. It makes a number recognisable on a receipt or in a chat, and it makes it clear which business an order belongs to. The prefix is derived from the business name, so it needs no setup.
The obvious implementation is to read the highest number and add one. Two tills confirming orders at the same moment would both read the same highest number, and both would claim the next one. This is a classic race.
Instead, the server keeps a counter and increments it atomically, inside the same database transaction that creates the order. The database guarantees that two concurrent transactions cannot receive the same value. Numbers are never handed out before an order truly exists, which is also why a new order is a draft until you press Confirm. A stray tap cannot burn a number.
A number can only be issued by the server, because the server is the one place that sees every till. So how does an offline till give an order a number?
It does not, at first. The desktop and Android tills create the order locally with a permanent internal identifier and show it as pending. The kitchen ticket prints straight away, because the kitchen needs the items, not the number. When the till reconnects, the order is sent to the server, receives its real number, and the local copy is updated.
The same idea makes retries safe. Each queued request carries an idempotency key. If the network drops after the server processed a request but before the till heard back, the retry is recognised and the original response is replayed rather than creating a second order.
A running number is unique and increasing, but it is not guaranteed to be gapless. If an order transaction is rolled back after a number was reserved, that number can be skipped in some designs. We do not promise an unbroken sequence, and you should not use order numbers as your only audit trail. Orders and their status history are kept separately for that.
Numbers also reflect the order in which orders reach the server, not the order in which a customer tapped the screen. An offline order confirmed at 7:00 pm but synced at 7:20 pm will be numbered after orders created online at 7:10 pm.
We traded the tidy feeling of "order 1 every morning" for numbers that are unambiguous. For a counter that wants short call-out numbers, that matters less than being able to find exactly one order later. If your team wants a short number for shouting across the kitchen, the last digits of the running number do the job.
To see how an order moves from draft to completion, read Taking orders, or learn how syncing works in Working offline.