The blog · 2026-07-31
The 214 is not an event record — and that's fine
Written for ED-1 — the supply-chain ISV / traceability-vendor engineering org — the integration engineer deciding what a carrier status is allowed to become.
One thesis: *the X12 214's carrier statuses are evidence about transport, not custody events — they carry no item-grain identifiers and no performer — so the correct compile is thin: a bol business-transaction reference plus corroborating context on transport-adjacent events, and never a fabricated ObjectEvent.*
This is a post about a compile we refuse to do. If you are evaluating this layer for your product, that refusal is the most useful thing on this page, because a pipeline that manufactures events from documents that never observed anything is a pipeline whose output you cannot defend later.
What a 214 actually asserts
The 214 — Transportation Carrier Shipment Status Message — is the carrier telling the shipper or consignee where a shipment stands: picked up, arrived at a terminal, out for delivery, delivered, exception. Structurally it hangs reference numbers off the shipment identification (the carrier's PRO, the shipper's ID, the bill of lading), then delivers status assertions with a code, a date-time, and a coarse geography. Segment-level detail is licensed X12 content, so per our standing rule it stays where it is legal and canonical: Stedi's 214 reference documents the structure; everything on this page is original prose over a self-authored synthetic fragment.
B10*4950532888*SHP20260728*SCAC~
L11*BM8842001*BM~
LX*1~
AT7*X6*NS***20260728*1433*ET~
MS1*CHICAGO*IL*US~
Read as claims: carrier SCAC, tracking PRO 4950532888, against shipment SHP20260728 and bill of lading BM8842001, reports status "arrived at delivery location" at 2026-07-28 14:33 ET, near Chicago. That is a real, useful assertion. Now look at what it does not contain.
The missing dimensions
An EPCIS event answers what, when, where, why — and the capture door adds who observed it. Hold the 214 against that:
- No what-grain. There are no SSCCs, no GTINs, no serials. The 214 talks about "the shipment" as an opaque unit named by reference numbers. You cannot populate an epcList or a quantityList from it without inventing contents it never asserted.
- No performer. Nobody scanned anything. There is no attested observer — no who — and who is never faked from a document. (Neither is it ever collapsed into capturedBy, which is the warrantor account that stamps a capture job — a different fact entirely.)
- Org-grain parties only. The parties are companies and a SCAC — the grain of a document header, not the grain of a dock door.
A compile that emits an ObjectEvent from this input is asserting an observation that never happened, performed by no one, about items it cannot name. Every downstream consumer — a reconcile job, a trace query, a counterparty auditor — inherits that fabrication.
Two candidate compiles, one refused
The wrong one, flagged so you recognize it in other people's pipelines:
// REFUSED — fabricates an observation
{ "type": "ObjectEvent",
"action": "OBSERVE",
"bizStep": "arriving",
"epcList": [],
"readPoint": { "id": "??" } }
An empty epcList because the document names no items; a guessed readPoint because "Chicago, IL" is not a read point; no observer because there was none. The event validates against nothing worth validating against.
The right one — thin by design:
// The compile: the document becomes a reference, not an event
{ "type": "bol",
"bizTransaction": "urn:epc:id:gdti:0614141.00777.BM8842001" }
The bol type is core CBV 2.0 §7.3 vocabulary, sitting beside po and desadv — a core field, not a custom extension. The reference lands on the events that do exist for this shipment: the shipping ObjectEvent and the AggregationEvent tree that the ASN compiled to, where item-grain identifiers and real capture provenance already live. The 214's status assertions ride as corroborating transport context against those events — evidence attached to the record, dated and attributed to the carrier document that made the claim.
Evidence-for versus record-of
That distinction is the design law, stated plainly: a document that reports on the world is evidence for the record; only an observation is the record. The ASN is a promise, the events are observations, the reconcile between them is a typed verdict — and the 214 is a third thing, a counterparty's narrative about the gap between shipping and receiving. The record stays defensible precisely because each of these keeps its own epistemic weight. When the exception views on visibility.cloud show a shipment stalled at a terminal, the underlying answer is honest about its source: the carrier said so, on this date, in this document — not we observed it.
Where real transport events come from
None of this means transport is invisible to the event record. Where the carrier's own systems emit genuine equipment events — DCSA-standard track and trace on the ocean side is the clean example, with defined event types, equipment identifiers, and timestamps published as an API standard — those compile as what they are: transport events from the party that performed them, with their provenance intact (the eBL post walks that lane). Parcel-carrier webhooks sit under the same law: rich enough to be excellent evidence, item-grain only when they genuinely carry the identifier, never laundered into observations. The rule is uniform, and it is the same rule that keeps the whole layer's output superset where a document carries more than the standard models and conformant always.
The engine's join verb enforces this ruling mechanically: a 214 in produces references and context out, and there is no flag to make it manufacture an ObjectEvent, because a flag like that is how a record stops being one. If your pipeline needs a carrier's word attached to a defensible event spine — rather than dressed up as the spine itself — that is exactly the compile this layer ships. If 214s are on your wire today, say so at the door — the onboarding flow asks which rails moved your freight last quarter and which of them reported on it.
964 words. The access flow is at /get-access/; the family's event door is epcis.dev.