The 856 advance ship notice is the transaction set that confuses people longest, and the reason is always the same: the HL loop. Everything else in X12 is a flat sequence of segments. The 856 is a tree encoded in a flat sequence, and you have to reconstruct it as you read.
BSN05 declares the structure. The most common value is 0001, meaning Shipment → Order → Packaging → Item:
Shipment (S)
└── Order (O)
└── Tare / pallet (T)
└── Pack / carton (P)
└── Item (I)
Not every 856 uses every level. A pick-and-pack ASN might go S → O → P → I with no pallet level. A bulk shipment might be S → O → I. The partner's implementation guide decides.
ST*856*0001~
BSN*00*SHIP-5521*20260801*1030*0001~
HL*1**S~
TD1*CTN25*4~
TD5**2*UPSN*M~
REF*BM*1Z999AA10123456784~
DTM*011*20260801~
N1*ST*ACME DISTRIBUTION CENTER*92*DC-04~
HL*2*1*O~
PRF*4500123456~
HL*3*2*P~
MAN*GM*00012345678000000123~
HL*4*3*I~
LIN**UP*012345678905~
SN1**24*EA~
HL*5*2*P~
MAN*GM*00012345678000000130~
HL*6*5*I~
LIN**UP*012345678912~
SN1**12*EA~
CTT*6~
SE*20*0001~
HL*4*3*I~
HL01 = 4 — this level's own ID. Increments across the whole transaction set, never resets.HL02 = 3 — the parent's HL01. This is the pointer that builds the tree.HL03 = I — the level code: Shipment, Order, Tare, Pack, Item.HL04 — optional child indicator, 1 if this level has children.So HL*4*3*I reads as: level 4 is an item, and it lives inside level 3. Level 3 was HL*3*2*P, a carton, which lives inside level 2, the order, which lives inside level 1, the shipment.
Trace the second carton the same way: HL*5*2*P — carton 5 hangs off level 2, the order. Not off carton 3. Getting this wrong is what produces ASNs where every carton nests inside the previous one, forming a chain a hundred levels deep instead of a hundred siblings.
This is the part that trips up people reading raw text. There is no closing marker for an HL loop. Every segment after an HL belongs to it until the next HL appears.
So MAN*GM*000123... after HL*3*2*P is the carton label for carton 3. The SN1**24*EA after HL*4*3*I is the quantity for the item in that carton. Read a segment against the wrong parent and the entire shipment is misinterpreted.
MAN*GM*00012345678000000123~
MAN01 = GM means the value is an SSCC-18 — the number encoded in the UCC-128 barcode physically stuck to that carton. This is the join between the electronic document and the physical box: the receiving dock scans the label, and the ASN tells them what should be inside.
If the MAN value doesn't match the printed label, the carton scans as unknown and the shipment gets handled manually — usually with a chargeback attached.
CTT*6~
In the 850 and 810, CTT01 counts line items. In the 856 it counts HL segments — six of them here, across all levels. Reusing 850 mapping logic for the 856 gets this wrong nearly every time, and the resulting file is rejected with a perfectly accurate but unhelpful error.
HL02 references an HL01 that already appeared.HL01 values are unique and ascending.BSN05.MAN if the partner requires labels.CTT01 equals the HL count.TD1.A structured tree view does most of this by rendering the hierarchy directly — a mis-parented carton becomes obvious the moment the tree is drawn, instead of after the partner rejects the file.
Related: decoding the 997 when an ASN is rejected.