blog · 2026-07-31 · written for: ED-2 — the RFID / scanning systems-integrator practice (the field deployment engineer commissioning a site under time pressure); B2D integration motion

What did I just scan? Payload identification from the first three bytes

One thesis: a scanner hands you bytes, not meaning — and the first three of those bytes, plus three structural checks, are enough to classify any payload deterministically. That classification is resolve's first job, and it is the job most site deployments improvise on commissioning day.

If you commission scanning sites for a living, you know the moment: readers are mounted, the network is up, and the first test scans land in a debug console as raw strings. Some start with ]C1. One has weird asterisks around it. One is an unpronounceable 30-digit run. The client asks what the system just read, and the answer is currently a shrug and a support ticket. This post is the shrug, replaced with a table.

The prefix your firmware has been sending all along

Almost every professional reader can prepend an AIM symbology identifier — a three-character prefix, ] + a code character + a modifier, standardized in ISO/IEC 15424 — telling you which symbology decoded and how. Most integrations throw it away in firmware config. Keep it: it is the single highest-value classification signal you get, because it distinguishes things the payload alone cannot.

The identifiers that matter on a dock or a line:

PrefixCarrierWhat the modifier tells you
]C1Code 128FNC1 in first position — this is GS1-128, the payload is AI syntax
]C0Code 128plain Code 128 — tracking numbers, internal codes, no AI promise
]E0EAN/UPC13-digit retail point-of-sale symbol
]I1ITFinterleaved 2 of 5 — on corrugate, almost always an ITF-14 case code
]A0Code 39plain Code 39 — VINs, asset tags, legacy labels
]d2Data MatrixECC 200 with FNC1 first — GS1 DataMatrix, AI syntax
]Q3QRFNC1 first — GS1-mode QR carrying element strings
]Q1QRordinary QR — if it holds a GS1 identity, it is a Digital Link URI, not an element string
]L2PDF417the driver's-license and logistics workhorse

Two entries in that table already prevent the most expensive class of confusion: ]Q3 and ]Q1 are both "a QR code," but one carries FNC1-delimited element strings a browser cannot read, and the other carries a URI. Same square, different grammar — and the AIM prefix tells you before you parse a byte.

Ten payloads, classified

Here is the cascade run the way barcoding resolve runs it, on ten raw payloads of the kind a commissioning day actually produces. <GS> marks the ASCII 29 group separator embedded by FNC1.

 1  ]E04006381333931
    → EAN-13 · GTIN, mod10 pass · canonical 04006381333931

 2  ]C101095060001343521726123110ABC123
    → GS1-128 · AI (01) GTIN + (17) expiry + (10) lot

 3  ]I110614141543219
    → ITF-14 · case-level GTIN, indicator digit 1, mod10 pass

 4  ]A0*1M8GDM9AXKP042788*
    → Code 39 · 17 chars after de-framing, no I/O/Q, position-9
      check digit passes 49 CFR 565.15 → VIN

 5  ]d201003400300114172801152010BC318<GS>21406014263816
    → GS1 DataMatrix · (01)+(17)+(10)+(21) — a DSCSA-shaped
      serialized drug payload

 6  ]Q3010950600013435210ABC123<GS>21987
    → GS1-mode QR · element string, (01)+(10)+(21) → SGTIN

 7  ]Q1https://id.gs1.org/01/09506000134352/21/1234
    → QR · GS1 Digital Link URI, primary key (01), qualifier (21)

 8  ]C01Z999AA10123456784
    → Code 128 · "1Z" + shipper + service + package id, UPS
      check character passes → tracking (ups-1z)

 9  ]C0420300249205500000000000000001
    → Code 128 · "420" ZIP routing prefix + "92" channel
      application id → USPS IMpb, MOD10 pass → tracking (usps-impb)

10  ]L2@ANSI 636014090002DL00410278ZC03190008DLDAQD1234562...
    → PDF417 · "@" + "ANSI " header → AAMVA driver's license.
      Parsed locally. Never enriched, never retained.

Three structural checks close what the prefix alone cannot:

  • FNC1 position. A leading <GS>-implying modifier (]C1, ]d2, ]Q3) is the GS1 marker. From there, AI parsing is mechanical: fixed-length AIs consume exactly their pinned length; variable-length AIs run to the next <GS> or end of data. Payload 2 parses without a single separator because every AI before the final (10) is fixed-length and (10) runs to end of data — the pinned AI table, not guesswork, is what makes that safe.
  • Framing. Code 39 transmits between *…* start/stop characters; most firmware strips them, some does not. Payload 4 is classified VIN only after de-framing, charset rejection of I/O/Q, and the federal check-digit pass — three independent gates before the word "VIN" is uttered.
  • Shape. A URI parses as a URI. A 17-char alphanumeric with a mod-11 pass is a VIN candidate. 1Z + 16, and 420-prefixed 22–30-digit runs, are carrier grammars with their own check rules — real schemes, just not GS1 ones, and the registry treats them as first-class rows.

The whole cascade — prefixes, AI lengths, framing rules, ambiguity ordering — ships as pinned registry data with published digests, not as code trapped in one vendor's firmware config. When two classifications are simultaneously possible, the ambiguity rule is explicit and versioned. You can diff it. You can cite it in a handover document.

Typed failure is part of the contract

The eleventh payload on a real site is the one nothing recognizes. What resolve returns then matters as much as the ten successes: exit code 1, and a typed error naming what was tried —

{"error":{"code":"unrecognized","message":"no scheme matched",
  "hint":"AIM ]C0; 11 chars; failed: gtin(length), ups-1z(prefix), sscc(length)"}}

— because "unknown, and here is why" is a fact you can put in a commissioning report, while a silent empty string is a callback in three weeks.

Run the table against your own readers before the client's first pallet arrives: npx barcoding.dev resolve takes the raw payload, AIM prefix and all, and returns the classification with the check-digit verdicts attached — pure and local, no network, no account, offline-tolerant on a dock with no signal. The full grammar of the AI system — fixed versus variable length, why the table is pinned data — is on the /schemes/ai registry page, and what happens the millisecond after classification is the rest of this arc.

Keys open the network half of the verb set. Get an API key — say what arrives at your door, and the provisioning order follows the list.

We answer in writing. We take at most five conversations a month, only when you ask for one, and only after you already have the written read.