blog · 2026-07-31 · written for: ED-3 — the platform / staff engineer who owns a shipping stack and has watched product identity vanish the moment a label prints; B2D connector-demand content

Tracking numbers are a scheme family too: 1Z, IMpb, and the SSCC nobody keeps

One thesis: carrier tracking numbers are proprietary identifier schemes doing the job the SSCC was standardized to do — naming a logistic unit — and because the parcel-API layer that mints them carries no GS1 identity at all, the product story of a shipment dies at the label and gets rebuilt downstream by guesswork.

If you build or maintain a shipping stack, you have seen the amputation happen live. Upstream, your systems know exactly what is in the box — SKUs, quantities, maybe GTINs. Then the shipment hits the label API, and everything the physical world will ever see of it is a carrier grammar: a 1Z, an IMpb, a FedEx number. The connector research behind the family's transaction layer verified this across the parcel tier, and the verbatim finding is worth keeping: the shipping APIs are "SKU-poor and GS1-blind."

The evidence, connector by connector

From the connector matrix, per vendor, checked against their own schemas:

  • EasyPost: tracking_code + carrier are the identity surface. No SSCC, no GLN, no GTIN anywhere; the CustomsItem object carries an HS code, and that is the closest thing to product identity in the API.
  • Shippo: carrier + tracking_number; customs items carry hs_code and a freetext sku_code. No GS1 identifier of any kind.
  • ShipEngine: tracking_number + carrier_code; customs products carry harmonized_tariff_code and sku. SSCC appears in exactly one carrier-specific corner.
  • FedEx (direct): the asymmetry that proves the point — FedEx Ground accepts SSCC-18 ("00") barcodes on labels per its Open Ship documentation, and the Ship commodity object can carry a GTIN. The standards hooks exist at the carrier; the aggregator layer above never passes them through.
  • UPS (direct): 1Z numbers only — no SSCC, no GTIN, no GLN anywhere in the public Shipping API schema.

So the pallet you built has two names. Inside your four walls it is an SSCC — the GS1 logistic-unit identifier, AI (00), the parent of every EPCIS AggregationEvent, the value your despatch advice transmits. Outside, it is a tracking number. Nothing in the parcel tier maintains the join, which is why "what products were on the shipment that just went sideways?" is a research project instead of a query.

The grammars, and what is actually checkable

Treating carrier formats as registry rows means stating, per row, exactly how far validation can go — and the three big rows land on three different tiers.

USPS IMpb — the fully open one. Publication 199 (Intelligent Mail package barcode Implementation Guide, v35, 2026-07-02) is freely downloadable from PostalPro, and it is a GS1 citizen: a GS1-128 barcode, Application Identifier 420 carrying the destination ZIP, channel-application identifiers (91–95 series) in front of a service type, mailer ID, and serial — closed by a MOD-10 check digit whose algorithm Pub 199 §4.6 publishes with a worked example. An IMpb validates offline, all the way, from a free primary source.

UPS 1Z — consensus grammar, unpublished arithmetic. The structure everyone implements — 1Z, six-character shipper number, two-character service code, seven-digit package serial, one check character — has no current official public specification behind it; the legacy developer-guide PDF that once described the check character is gone. So the registry row is honest: resolve parses the consensus structure and labels the check best-effort reconstruction, never "verified per UPS specification," because no such public specification presently exists to cite.

FedEx — proprietary end to end. The 12/15/20-digit formats have no public primary source at all; structure is known from labels, not specs. The row parses, extracts, and says exactly that.

$ barcoding resolve '(420)94581(92)…' --json
{"scheme":"usps-impb","ai":{"420":"94581"},"channel":"92","stc":"…","mid":"…",
 "check":"mod10 pass (Pub 199 §4.6)"}

$ barcoding resolve 1Z999AA10123456784 --json
{"scheme":"ups-1z","shipper":"999AA1","service":"01","serial":"2345678",
 "check":"best-effort (no public UPS algorithm)"}

Two rows, two different strongest-available claims, both typed in the output. That difference is the scheme registry working.

What the label API loses that the despatch advice keeps

The despatch advice — the ASN your EDI layer sends — is the document that still knows both names: it carries the SSCC in its shipment marks and the item detail under it, which is why the ASN is where the pallet's two identities were last seen together. The transaction layer of this family, transactions.dev, holds that side of the join; the identity layer's job is the repair verb on this side: given a tracking number and whatever fragments the parcel API kept (an HS code, a freetext SKU), bridge produces GTIN candidates with confidence and cited evidence — never a silent best guess, and exit code 1 when no candidate clears the floor. Candidates-with-evidence is the only honest posture on a join the infrastructure itself discarded.

One more line for the registry's honesty column: tracking status — where the package is now — is a walled garden per carrier terms, and it stays per-caller, on the caller's own carrier credentials, uncached beyond what each carrier permits. Identity is the open layer; status never was. The rows keep those separate so the product cannot quietly promise what the licenses forbid.

Run it

npx barcoding.dev resolve on the last tracking number in your inbox tells you which grammar you are holding and how far its validation can honestly go; /schemes/tracking is the row-by-row reference, and /schemes/sscc is the identifier your pallet deserved to keep. If the missing join — tracking number back to product identity, with evidence attached — is the thing your stack rebuilds by hand every quarter, that is the bridge rail: tell us who you are.

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.