Shipmind Labs

Two invoices issued in the same second, one number. That is not a race condition you fix later — that is an accounting document you now have to explain to an auditor.

Most teams treat the invoice number as a formatting concern. Take a counter, add a prefix, pad it to five digits, render it on the PDF. It works in development, where requests arrive one at a time.

Then two workers hit the same series concurrently. You get a duplicate, or you get a gap — and a gap is not neutral either. In several VAT regimes the sequence itself is the thing being audited: numbers within a series and period must not repeat and must not skip. A missing number reads as a deleted invoice until you prove otherwise.

The fix is boring and structural. The number is allocated by the store, per series and per period, under a lock the database owns — not computed in application code and hoped to be unique. Application code decides which lines appear: domestic sale, private buyer, reverse charge. The store decides which number is legal.

We pulled this apart while building euinvoice, our open-source invoicing work. The split that made it survive: VAT logic is a pure function of the transaction, numbering is a transactional guarantee of the storage layer. Mixing them is how teams end up retro-editing issued documents.

One consequence worth planning for early: a failed invoice after allocation still consumes a number. You cancel it, you do not reuse it.

How does your system handle an invoice that fails validation after the number is already allocated?

Was this useful?

Building something similar?

or email hello@shipmindlabs.com