# The 214 is not an event record — and that's fine

> transactions.dev · by visibility.cloud — 2026-07-31
> Written for 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](https://www.stedi.com/edi/x12-008010/214)
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 interface 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:

```json
// 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:

```json
// 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](/blog/biztransaction-is-a-core-field/). 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](/blog/reconcile-is-a-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](https://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](/blog/dcsa-ebl-compiles-to-bol/) walks that lane).
Parcel-carrier webhooks sit under
[the same law](/blog/delivered-webhook-is-evidence/): 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](/get-access/) — the onboarding flow asks which
rails moved your freight last quarter and which of them reported on it.

---
Access: https://transactions.dev/get-access/ · All posts: https://transactions.dev/blog/ · Machine face: https://transactions.dev/llms.txt
