The blog  ·  2026-07-31

UNA is a courtesy, not a mystery — the EDIFACT envelope for people who learned X12 first

Written for ED-1 — the supply-chain ISV / traceability-vendor engineering org — the integration engineer whose first international partner just sent a DESADV.

One thesis: EDIFACT's service segments do the same envelope work X12's do — with defaulted delimiters instead of declared ones, one less nesting level by default, and an escape character X12 never had — and every difference an integrator actually hits fits on this page. If you learned on ISA and ST, you already understand UNB and UNH; what follows is the delta, not a second education.

UNA: six characters, all optional

Where X12 declares its delimiters by position in a mandatory header, EDIFACT ships defaults and lets a file override them. The override is the UNA segment — the string UNA followed by exactly six characters, in fixed order:

UNA:+.? '
   │││││└─ segment terminator        (')
   ││││└── repetition separator      (space = unused, pre-D.99 files)
   │││└─── release (escape) char     (?)
   ││└──── decimal mark              (.)
   │└───── element separator         (+)
   └────── component separator       (:)

No UNA, and the defaults apply — which are exactly the characters shown. In practice most files either omit UNA entirely or send it carrying the defaults anyway, as a courtesy to naive readers. A correct lexer honors it when present and assumes the defaults when absent; that is the entire delimiter story, and it is one if statement where X12's is four positional reads.

The envelope levels, X12-to-EDIFACT

Level by level, over synthetic fragments:

interchange   ISA … IEA            ↔   UNB+UNOA:3+SELLERGLN:14+BUYERGLN:14+260731:0915+101'
                                       … UNZ+1+101'
group         GS … GE              ↔   (UNG … UNE — optional, rarely used)
message/set   ST*856*0001 … SE     ↔   UNH+1+DESADV:D:96A:UN:EAN005'
                                       … UNT+7+1'

What maps directly: UNZ echoes the interchange control reference from UNB and asserts a count, exactly like IEA; UNT asserts the message's segment count (including UNH and UNT) and echoes the message reference from UNH, exactly like SE — so the six agreement invariants port with the segment names swapped and one difference in what the count field covers.

What does not map: the functional-group level is optional in EDIFACT (UNG/UNE exist but most interchanges skip them), so the default nesting is two levels, not three — UNZ's count is then messages, not groups. And the UNH carries what ST never had room for: the full message identity — type DESADV, version D, release 96A, controlling agency UN, and an association code like EAN005 naming the EANCOM subset. Where X12 puts the version on the group (GS08), EDIFACT puts it on every message, which is operationally kinder: a mixed-version interchange is self-labeling.

Two smaller deltas an integrator hits in week one: EDIFACT composites are first-class and everywhere (X12 uses its component separator sparingly; EDIFACT's : is structural in most segments), and numeric conventions differ — the UNA even declares the decimal mark, because 1234,56 is a legal way to say what X12 would only ever write as 1234.56.

The ? mechanic X12 doesn't have

X12 has no escape character: if your data contains the element separator, you have a problem the standard does not solve for you. EDIFACT solves it — the release character ? neutralizes the following character, so O?+M is the literal string O+M, ?? is a literal ?, and a company named Smith ? Sons survives the wire. The lexer consequence: an EDIFACT tokenizer is a two-character lookahead machine, and a byte-exact round-trip must preserve release sequences as sent, not re-derive them — the emit(parse(x)) === x law counts ?+ and any semantically equivalent re-escaping as different bytes, because they are.

Why this rail gets the deep reference

There is a licensing asymmetry under this post. X12 sells access to its standard, so our X12 pages are original prose with segment detail linked to the licensed reference, never republished. UNECE publishes the complete UN/EDIFACT directories free of charge — which is why the EDIFACT side of the family reference goes dictionary-deep, with every vendored directory file sha256-pinned under the same journaled-ruling governance as the family's GS1 artifacts. The flagship walkthroughs are live: the EANCOM DESADV — the international ASN, the message the UNH above introduces — and EDIFACT ORDERS, its purchase-order counterpart.

That DESADV is not a curiosity. GS1's own adoption numbers put EANCOM far ahead of GS1 XML in installed base, and the DESADV compiles onto the event record exactly as the 856 does — CPS hierarchy in place of HL loops, NAD-carried GLNs landing in sourceList and destinationList, SSCCs into the aggregation tree (the X12 twin of that story), and the whole output validating against the pinned official EPCIS 2.0 schema. Conformant, and a superset where the message carries more than the standard models — the pairing that holds everywhere in this family.

The one-page summary

Reading an EDIFACT interchange after years of X12: honor UNA or assume its defaults; expect two envelope levels, not three; take the message identity from UNH, not the group; port the count-and-echo invariants as-is; respect ? in the lexer; and let the decimal mark surprise you only once. The parse, validate, and compile verbs treat both rails as dialects over one canonical form — when your first DESADV arrives, the pipeline that lands it on the record is behind the access flow, and the survey asks which rail your partners speak precisely so the right reference meets you at the door.


865 words. The access flow is at /get-access/; the family's event door is epcis.dev.