Every barcode, read and verified

You already scanned it.
You kept a twelfth.

barcoding.dev reads every barcode a scanner can — GS1, VIN, ISBN, UDI, NDC, SSCC, tracking numbers — checks it from the digits alone, and splits what it said: the product code to the register, the expiry, lot and serial out the other side as named fields. On your machine, no key.

the label GS1-128 · 321 modules at one pixel each
(01)09506000134352(17)261231(10)ABC123(21)1234

what it said

(01)09506000134352(17)261231(10)ABC123(21)1234

check mod10 pass — computed from the digits

the register takes this

(01) 09506000134352 product code (GTIN)

the price lookup, exactly as it happens today

and drops these

(17) 31 Dec 2026 expires
(10) ABC123 batch / lot
(21) 1234 serial number

the floor

Why does anyone want a barcode?

A barcode was wrapped around your wrist minutes after you were born. It gave you a name a stranger could read without waking you. That is the whole idea, before a single acronym, and it is everywhere in the room you are standing in right now.

  • The story

    Six things in a room, drawn wearing their real barcodes, and what each one means: a kind, or this one.

  • The periodic table of visibility

    Nine barcode formats, the things they name, and the door in the family that owns each part, on one plate.

Fork the scan

From December 2027 the register reads the whole square, and keeps the part it already had.

GS1's Sunrise 2027 program expects retail point of sale to read 2D barcodes by the end of December 2027 and take the GTIN from them. That is the whole obligation; the six things it is claimed to require are on the blog, each against its source.

When a brand encodes lot, expiry and serial, all of it arrives in the same square on the same scan. Every US prescription-drug package already carries exactly that. The register takes the GTIN for the price lookup and drops the rest, because a sale record is item, price, basket.

So fork it. The GTIN goes to the register untouched. Lot, expiry and serial go out the other side as named fields, checked from the digits alone. No new step for a cashier, no new hardware: an imager that clears the 2027 date already reads the whole square.

What happened, where and who did it becomes an event at epcis.dev; rolled up across stores and docks, it is visibility.cloud. barcoding.dev holds no history.

Eight verbs, on your machine.

--json on every verb, typed errors on stderr, exit codes 0, 1 and 2. The same engine runs behind npx barcoding.dev and the hosted doors here; four of them are listed as MCP tools — resolve, verify, generate, pins — all readOnlyHint: true; the rest are reachable on the CLI door only.

Four movements, in order: read a barcode, draw one, create an identifier for a thing that has none, and say what it means.

verbwhat it doesnetworkexit-1 verdict
decodea frame or a photo → what the barcode actually says. Runs on the hosted door and, unchanged, in the browser at /scan — frames are decoded in memory and discarded, never stored, never loggedpure · localnothing decodable in the frame
resolveany identifier-bearing string — what a scanner read, bare GTIN-8/12/13/14, EPC URN, GS1 element string, GS1 Digital Link URI, VIN, ISBN, SSCC, tracking number — to canonical identity: scheme, canonical form, parsed AIs and fieldspure · localunrecognized / unparseable
verifycheck digit + structure + prefix legitimacy (GS1 prefix ranges → issuing MO; WMI → manufacturer; ISBN group), from pinned tablespure · localfails validation
generatethe write-side twin of resolve: id + AI map → element string, Digital Link URI, rendered symbol (QR / DataMatrix / GS1-128 / ITF-14). resolve(generate(x)) === x is the round-trip lawpure · localunencodable input
serializenothing → one serial, derived from the request with no stored counter, on a GS1 AI(21)-safe alphabet. Free and transparent: the response states, in the response, exactly what the serial disclosespure · local—
pinsprint the pinned artifact and data-source-manifest digestspure · local—
versionpackage, engine-core and pin-set versionspure · local—
mcpthe agent door on stdio: the tarball's verbs as MCP tools, generated from the same table, readOnly-hinted——

The thing that has no barcode.

A model can read a label, judge the damage on a carton and count the cases on a pallet. It cannot tell which one it is. Either the thing says so, or nobody knows.

Most of what moves in a building has no identifier at all: totes, bins, returnable crates, a pallet built forty minutes ago, a dock door, a rack position. serialize gives one of them a number, with no license to buy, no membership, no key and no account. One curl, and the number is yours.

The identifier is derived from the request, not a counter, so there is no range to run out of. Serials that must reveal nothing are a different, paid class.

$ curl -sX POST https://api.barcoding.dev/serialize

{
  "serial": "Gs21hefO3IX74Lfk",
  "profile": "T1 compact",
  "alphabet": "tsp-1",
  "decodes_to": { "issued_at": "2026-08-05T11:12:52.000Z", "entropy_bits": 48 },
  "discloses": ["issuance time (1 s precision)"],
  "honesty": "This serial decodes publicly to: issuance time (1 s precision). A collection of our serials therefore reveals issuance volume and cadence, business hours and timezone. That is the disclosed cost of free + stateless + transparent. If serials must reveal nothing, that is the opaque class."
}

The provenance envelope.

Per attribute, not per record — because real records are mosaics: nutrition may be public-domain USDA while the category is ODbL Open Facts. The license class travels with the value, so a downstream agent can filter by what it is allowed to do with each field.

{
  "attribute": "servingSize",
  "value": "30 g",
  "source": {
    "id": "usda-fdc",
    "record": "https://fdc.nal.usda.gov/…",
    "dataset_version": "FDC 2026-04 full download",
    "digest": "sha256:…"
  },
  "license": "public-domain",
  "fetched_at": "2026-07-31T18:20:11Z",
  "confidence": 1.0
}

The barcode registry.

One pinned row per identifier family: the grammar, the check digit, the canonical form, the barcode types it rides, the enrichment sources with their license class, and the join into the event record. GS1 is the largest family in it, not the boundary.

schemevalidation railenrichment raillicense class
GTIN / GLN / SSCCGS1 GenSpecs mod-10, prefix rangesfood: USDA FDC (CC0) + Open Facts (ODbL, segregated)public-domain · share-alike-odbl
VIN49 CFR 565.15 — transliteration, weights, mod-11NHTSA vPIC (public domain); auto.dev as the owned railpublic-domain · first-party
UDI (GS1 / HIBCC / ICCBBA)FDA UDI formats docAccessGUDID / openFDA (CC0; GMDN fields stripped)public-domain
NDCstructural (no check digit)openFDA drug/ndc, updated daily (CC0)public-domain
ISBN (978/979 — a valid GTIN-13)free ISBN Users' Manualrouted to book enrichmentopen · confirm-before-redistribution
USPS IMpbPub 199 MOD10, worked example publicidentity open; tracking status per-calleridentity: open · status: per-caller
DL/ID PDF417 (AAMVA)parse and verify onlynone — statutoryno_retention, hard flag

Seven laws, not seven features.

The parts that cannot be renegotiated later.

  1. 01

    No bare value anywhere.

    A resolve answer says what was computed from the digits and what was looked up, and every enriched attribute travels in a provenance envelope: source, license class, fetched-at, digest.

  2. 02

    Identity is free. It stays free.

    resolve, verify and generate are pure and local: no network, no account, no key. The validation layer of the physical world is public regulation and royalty-free standards.

  3. 03

    License-clean rails only.

    USDA FoodData Central (CC0), openFDA (CC0), NHTSA vPIC (public domain), the Open Facts family (ODbL, as a segregated layer). No scraped aggregator, ever.

  4. 04

    Sources are pinned like schemas.

    Each source's manifest records the license text, its retrieval date and its sha256; an upstream license change is a failed pin, not a silent drift. pins prints the digests.

  5. 05

    Conformant to the standard; explicit beyond it.

    For GS1 keys the /01/* door serves the GS1-Conformant Resolver surface, RFC 9264 linksets and /.well-known/gs1resolver, as a delegating door: resolution is id.org.ai's. Every other family gets the same contract, labeled as an extension.

  6. 06

    One door for people and for agents.

    The same verb set over MCP; resolve and verify ship readOnlyHint: true with complete tool descriptions. Refusals are typed errors, never fabricated answers.

  7. 07

    Joined, not adjacent.

    A serialized 2D scan constructs a valid EPCIS 2.0 ObjectEvent, validated against epcis.dev's pinned schema; its bizTransactionList carries the PO/ASN context via transactions.dev; the attested observer rides in id.org.ai terms.

Get an API key.

The local verbs run from npx barcoding.dev today with no key. A key opens the network half of the verb set.