Unique QR codes and serialisation
A QR code program is only as strong as its codes, and code design is one of the few parts of this business where a decision made in an afternoon can cost a company crores two years later. The failure is always the same shape: codes that can be predicted, and therefore claimed without ever buying the product.

Serialisation means generating a unique code for every product unit from a large sparse keyspace, so that valid codes are a vanishingly small fraction of all possible codes and cannot be guessed. Each code is mapped to a SKU and batch, printed with variable-data printing, and reconciled between codes generated, printed and shipped.
Why keyspace is the whole security model
There is no cryptography protecting a QR code on a carton — anyone can photograph it. The only thing preventing someone from fabricating valid codes is that guessing one is arithmetically hopeless. That property comes from keyspace density: the ratio of codes you have issued to codes that could exist.
| Design | Possible codes | Issued | Chance a guess is valid |
|---|---|---|---|
| 6-digit sequential number | 1,000,000 | 800,000 | 80% — trivially exploited |
| 8 alphanumeric characters | ~2.8 trillion | 10 million | ~1 in 280,000 |
| 12 alphanumeric characters | ~4.7 × 10^18 | 100 million | ~1 in 47 billion |
The first row is not hypothetical. Sequential or near-sequential numbering is the most commonly exploited weakness in Indian QR programs, because the attack requires no skill: claim code 100001, then 100002, and continue.
The four properties a code must have
Sparse
Issued codes must be a tiny fraction of possible codes. Twelve alphanumeric characters gives ample headroom for any Indian brand's volumes.
Non-sequential
Codes must be drawn randomly from the keyspace, not incremented. Two codes printed consecutively should share nothing.
Check-digited
A check digit lets your server reject malformed guesses arithmetically, before a database lookup. This matters at scale: it turns a probing attack into a cheap rejection rather than an expensive query.
Rate-limited on validation
Even a sparse keyspace can be probed with enough attempts. Cap validation attempts per device and per IP, and alert on probing patterns.
Mapping codes to products
A code is useless without the record behind it. At minimum, each issued code should map to:
- SKU and pack size — so the reward rate can differ by product.
- Batch or lot — so a recall can invalidate a range of codes.
- Production date and line — so a print-quality problem can be traced.
- Intended market or state — so cross-territory arbitrage is visible.
- Claim status and timestamp — the operational heart of the system.
That batch mapping is what lets you do the single most useful thing in a recall: invalidate every code in a batch instantly, so a recalled unit cannot be claimed or verified as genuine.
The reconciliation nobody plans for
Three numbers must agree at the end of every production batch, and they never do without deliberate effort:
- Codes generated — what your platform issued.
- Codes printed — what the line actually applied, minus rejects.
- Codes shipped — what left the factory on a despatch document.
The gap between them is where codes go missing, and missing codes are the raw material of fraud: an unprinted or rejected code that is still valid in your database can be claimed by anyone who obtains the list. Reject handling should invalidate the code, not just discard the label.
How many codes will you need?
Size the keyspace for the life of the program, not the first year. A brand producing 40 million units a year with a ten-year horizon needs 400 million codes, and should be issuing from a keyspace many orders of magnitude larger. Codes are cheap to generate and impossible to widen retrospectively without breaking every code already in the field.
One code or several?
Many Indian programs now run two layers — an outer code on the carton and an inner code inside the pack. The outer proves the packaging is genuine; the inner proves the contents are, which is what defeats a repacker who has obtained real cartons. It costs a second print operation and materially raises the difficulty of counterfeiting. The same logic applies to in-pack versus on-pack placement.
Questions to ask a platform vendor
- What is the keyspace, and how is randomness generated?
- Can we invalidate an entire batch in one action, and how fast does it propagate?
- What happens when the same code is scanned in two districts within a second?
- How are print rejects reconciled against issued codes?
- What is your peak validation throughput, from a live account rather than a benchmark?
- Can we export the full code database if we leave?
Frequently asked questions
What is QR code serialisation?
Serialisation is generating a unique code for every product unit rather than repeating one code across a production run. Each code is drawn randomly from a large sparse keyspace, carries a check digit, and is mapped to a SKU, batch, production date and claim status so it can be validated, rewarded and invalidated individually.
Why should QR codes not be sequential?
Because sequential codes can be guessed with no skill at all — claim code 100001, then 100002, and continue. Sequential or near-sequential numbering is the most commonly exploited weakness in Indian QR programs. Codes must be drawn randomly so that two codes printed consecutively share nothing.
How many characters should a QR code have?
Twelve alphanumeric characters gives roughly 4.7 × 10^18 possible codes, so issuing 100 million leaves the chance of a random guess being valid at about one in 47 billion. Eight characters is usually adequate at smaller volumes. Size the keyspace for the life of the program, since it cannot be widened later without invalidating codes in the field.
What is a check digit used for in a QR program?
It lets your server reject malformed or guessed codes arithmetically before performing a database lookup. At scale this matters operationally as well as for security, because it converts a probing attack into a cheap rejection instead of millions of expensive queries.
How do you handle a product recall in a QR program?
By invalidating every code mapped to the affected batch in a single action, so recalled units can no longer be claimed for rewards or verified as genuine. This requires that codes were mapped to batch and production date at generation, which is why batch mapping is part of the initial design rather than an afterthought.
What is code reconciliation and why does it matter?
It is confirming that codes generated, codes actually printed after rejects, and codes shipped all agree at the end of a batch. The gap between those numbers is where valid but unprinted codes go missing, and a valid code that never reached a product can be claimed by anyone who obtains the list.