# Coupon QR codes — how they work

> A coupon QR code carries a code or a link to an offer page. The critical design fact is that any printed coupon code is a shared secret: photograph it once and it spreads. Enforce limits server-side at redemption, never in the QR code itself.

Source: https://useqr.app/coupon-qr-code · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## Three shapes, three risk levels

**Plain text code.** The payload is just `SAVE20`. Simple, works offline, and instantly
shareable — treat it as public the moment it is printed.

**Link to an offer page.** `example.com/offer/spring` — you control the page, so you can
end the offer, measure scans and change terms. Still shared as easily as any link.

**Unique per-code token.** `example.com/c/7f3a91b2` with one row per token in your
database. The only shape that supports genuine one-per-customer limits, and the only
one that needs bulk generation.

## Enforce limits where they can be enforced

Nothing inside a QR code can limit its own use. No expiry field, no counter, no "single
use" flag exists in the QR standard, and anything you put in the payload can be read
and reused. Expiry and redemption limits live in your system, checked at the moment of
redemption. A code that says `EXPIRES-2026-09-01` in its text expires exactly when your
till says it does, and not before.

## Bulk unique coupons

For per-customer codes, generate a CSV of tokens and run it through a bulk generator.
Practical notes:

- Use non-sequential tokens. `c/0001`, `c/0002` invites guessing.
- 8–10 characters of base32 is plenty and keeps codes coarse and scannable.
- Avoid ambiguous characters if humans might type it as a fallback: no `0`/`O`,
  no `1`/`l`/`I`.
- Print the token as text next to the code so a failed scan is not a lost sale.

UseQR's [bulk tool](/bulk) takes a CSV and returns a ZIP, a grid PDF, or Avery-format
label sheets, and decode-verifies every code before you print a thousand of them.

## Fraud in the physical world

The realistic attacks are dull: a customer photographs the coupon and shares it, or
someone pastes their own sticker over your code. Defences that work — server-side
redemption limits, staff who read the confirmation screen rather than the sticker, and
printing the offer terms in text so a substituted code is visibly wrong.

## FAQ

### Can a QR code expire on its own?
No. The QR standard has no expiry field and nothing inside the payload can enforce anything. Expiry and redemption limits are enforced by your system when the code is presented.

### How do I make a single-use coupon?
Generate one unique token per customer, print one code each, and mark the token redeemed in your database at the till. That is the only shape that supports a real limit.

### Should the coupon code also be printed as text?
Yes. A failed scan then costs nothing — the customer reads the code aloud instead of walking away. Use characters that are unambiguous when read.

### How do I make thousands of unique coupon codes?
Generate a CSV of non-sequential tokens and run it through a bulk generator that returns a ZIP or a label-sheet PDF. UseQR's bulk tool also decode-verifies every code before you print.

## Try it

- https://useqr.app/coupon
- https://useqr.app/url
- https://useqr.app/text
