The launch journal

An 856 is an aggregation tree wearing a trench coat.

Strip the envelope off an X12 856 and what remains is a tree. The despatch advice describes a shipment that contains orders, orders that contain packs, packs that contain items — a rooted hierarchy the message spells out one node at a time, each node naming its parent. That is also, exactly, the shape of the EPCIS aggregation model: an SSCC parent, its children, and the events that assert containment. The mapping between the two is not a heuristic. It is deterministic, and this post walks it on a worked pair.

The tree, in original prose

The 856 builds its hierarchy with a repeating structural segment: each occurrence carries its own sequence number, a pointer to its parent's number, and a level code — shipment, order, tare, pack, or item. Reading the segments in order and following the parent pointers reconstructs the tree; nothing about the nesting is implicit. Pack-level nodes carry the marks physically applied to the freight — in GS1 practice, the SSCC of the pallet or case. Item-level nodes carry the trade item and its quantity: the GTIN, and where serialization applies, the serials; where lot-tracking applies, the lot.

That is all the structure this mapping needs, stated in our own words. For element-by-element segment detail, use Stedi's X12 856 reference — the canonical public reference, credited here and linked, never copied. (Why we link instead of republishing is its own post.)

A self-authored fixture

This wire document is synthetic — authored for this corpus, no partner's implementation guide reproduced:

ST*856*0001~
BSN*00*5501*20260729*0712~
HL*1**S~
DTM*011*20260729~
REF*BM*80144100~
N1*SF*ACME FOODS*UL*0614141007776~
N1*ST*NORTHDOCK DC*UL*0614142008888~
HL*2*1*O~
PRF*PO-06012-1234~
HL*3*2*P~
MAN*GM*006141410000055012~
HL*4*3*I~
LIN**UP*614141073467*LT*7A-4412~
SN1**96*EA~
CTT*4~
SE*16*0001~

One shipment, one order, one pallet, one lot-tracked line: 96 each of GTIN 614141073467, lot 7A-4412, on SSCC 006141410000055012, shipped 2026-07-29 against PO-06012-1234, ship-from and ship-to identified by GLN.

The mapping table

ASN factsourceEPCIS landing zone
shipment noderoot of the hierarchyshipping ObjectEvent, bizStep: shipping, disposition: in_transit
pack node + markpack level, SSCC in the marks segmentAggregationEvent, parentID = SSCC EPC URI
item node, serializeditem level, GTIN + serialschildEPCs as SGTIN URIs
item node, lot-grainitem level, GTIN + lot + quantitychildQuantityList as LGTIN + quantity + UoM
ASN numberBSN02bizTransactionList: { "type": "desadv", … }
PO numberPRFbizTransactionList: { "type": "po", … }
bill of ladingREF (BM)bizTransactionList: { "type": "bol", … }
ship-from / ship-to GLNsparty loop, GLN qualifiersourceList / destinationList (owning_party, location)
despatch dateDTM (011)eventTime of the shipping event

Every row lands on a core field. No extensions, no invented vocabulary — this is the machinery CBV built for exactly this document set.

The output, validated

biztx join emits the event skeleton; here is the expected-output fixture for the document above, from the corpus pair. The aggregation event:

{
  "type": "AggregationEvent",
  "parentID": "urn:epc:id:sscc:0614141.0000005501",
  "childQuantityList": [
    { "epcClass": "urn:epc:class:lgtin:0614141.007346.7A-4412",
      "quantity": 96, "uom": "EA" }
  ],
  "action": "ADD",
  "bizStep": "packing",
  "bizTransactionList": [
    { "type": "desadv",
      "bizTransaction": "urn:epc:id:gdti:0614141.11711.5501" }
  ]
}

and the shipping event carries the SSCC in epcList, all three document references, and both parties. The whole pair validates against the pinned official schema:

$ npx epcis.dev validate 856-expected.epcis.json
valid	schema=epcis-json-schema.json	version=2.0.1
$ npx epcis.dev hash 856-expected.epcis.json
hash	0	ni:///sha-256;a10cc2beddbd2cc3757d1efd00e9a5359cb9734440678d946dd6974e69a7da74?ver=CBV2.0
hash	1	ni:///sha-256;2ae830781eb07477910e75430daea6c1bea8fd04ad44bd1ac168e8b1daa8d8b0?ver=CBV2.0

Validation is the acceptance gate: an event the pinned EPCIS 2.0.1 schema rejects never leaves the join. And because identity is the CBV §8.9 content hash, the same ASN mapped twice produces the same events — replays cost nothing.

What the mapping refuses to invent

A deterministic mapping is honest about what the document does not know. An 856 asserts what the shipper says was packed and shipped — so the join emits packing and shipping events with the despatch date the document itself carries, and it stops there. It does not fabricate a receiving event, a commissioning time, or a business step the document never witnessed. Missing quantities, an orphaned parent pointer, a cycle in the hierarchy: each is a typed rejection naming the node, never a silently pruned tree. The events that say what actually arrived come from your scanners — and diffing the two is the entire receiving story.

The EDIFACT twin of this mapping — DESADV, at full open-content depth — is here, CPS packing tree and all.

Validate the fixture pair now with npx epcis.dev validate — no account, exit code is the verdict. Run your own ASNs through the join: the document verbs ride the capture surface — get a capture key.

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.