GS1 Digital Link QR
GS1 Digital Link is a URL syntax that encodes product identifiers (GTIN, lot, serial, expiry) as path segments after a base hostname — so a single QR code is both a human-friendly link and a machine-parseable product identifier. Retail buyers (especially DACH grocery), EU pharma post-FMD, and supply-chain auditors increasingly require GS1-conformant QR codes on packaging instead of standalone 1D barcodes.
Reference: GS1 Digital Link spec .
URL syntax
The encoded URL has the form:
https://<host>/01/<gtin>[/10/<lot>][/17/<expiry>][/21/<serial>]| AI | Meaning | Format |
|---|---|---|
01 | GTIN (mandatory) | 8, 12, 13, or 14 digits |
10 | Batch / lot | up to 20 alphanumeric chars |
17 | Expiry date | YYMMDD |
21 | Serial number | up to 20 alphanumeric chars |
The order in the URL is AI numeric order (01 → 10 → 17 →
21), not the order you fill the form. Most parsers tolerate any
order, but emitting in numeric order keeps you portable.
Endpoint
POST /v1/qr/gs1Body:
{
"host": "b.elido.me",
"gtin": "09520123456788",
"application_identifiers": {
"lot": "ABC1",
"serial": "SN001",
"expiry": "270101"
},
"format": "png",
"error_correction": "Q",
"size": 1024
}Response:
{
"url": "https://b.elido.me/01/09520123456788/10/ABC1/17/270101/21/SN001",
"png": "<base64 bytes>"
}The endpoint returns:
200—{ url, png|svg }. Useformat: "svg"for vector printing.400— missinghostorgtin, unparseable JSON, unknownformat.422— GTIN check digit mismatch, invalid AI value (lot too long, expiry not YYMMDD, etc).
Worked example 1 — milk carton
A litre of organic milk with a printed lot code, no serial, no expiry on the QR (the human-readable best-before date stays on the label):
curl -X POST https://qr.elido.app/v1/qr/gs1 \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"host": "b.elido.me",
"gtin": "09520123456788",
"application_identifiers": { "lot": "L260509A" },
"format": "svg",
"error_correction": "Q"
}' \
--output milk.jsonThe QR encodes:
https://b.elido.me/01/09520123456788/10/L260509AA buyer scanning this with a phone gets a landing page (your dashboard
chooses what to render); a warehouse imager parses the path and
extracts GTIN 09520123456788 + lot L260509A for stock rotation.
Worked example 2 — OTC pharmaceutical (FMD-aligned)
EU Falsified Medicines Directive requires GTIN + serial + expiry + lot on every commercial pack. The QR carries all four:
curl -X POST https://qr.elido.app/v1/qr/gs1 \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"host": "b.elido.me",
"gtin": "04006381333931",
"application_identifiers": {
"lot": "B22A41",
"serial": "PFX9000123",
"expiry": "281231"
},
"format": "svg",
"error_correction": "H"
}' \
--output pharma.jsonThe QR encodes:
https://b.elido.me/01/04006381333931/10/B22A41/17/281231/21/PFX9000123Use
error_correction: "H"for pharma. Pharma cartons see harsh handling; H-level (≈30% recovery) tolerates scuffs that would kill a Q-level code.
Validating GTINs
The endpoint validates the GS1 mod-10 check digit before
generating. Invalid GTINs come back as 422 with a stable error
message:
{ "error": "invalid GTIN: check digit mismatch (expected 8, got 7)" }The check digit is the right-most digit; it’s computed by alternately
weighting the other digits by 3 and 1 (right-to-left, starting with
3) and taking (10 - sum mod 10) mod 10. The dashboard’s GTIN field
runs the same check live as you type — paste the 13-digit body of
your EAN and the field shows you the expected check digit.
Quiet zone & error correction
The renderer emits a 4-module quiet zone on every side, matching the GS1 General Specs §5.5.2.5 minimum. You don’t need a separate “GS1 mode” flag — the default rendering pipeline is conformant.
For error correction:
Q(≈25% recovery, our default) — fine for retail packaging on glossy stock.H(≈30% recovery) — required for pharma, recommended for uncoated cardboard or anywhere a printer might smudge.LandM— not recommended for packaging; only for digital display or paper handouts.
Tier gate
GS1 QR is a Business+ feature on the dashboard. The endpoint
returns 402 Payment Required for lower tiers; the UI greys the form
and shows an upgrade CTA.
See also
- QR codes — branded QR codes for short links.
- Custom domains — set up your own host for the GS1 URL prefix.