# Every wire format is a dialect. The transaction is the noun.

> transactions.dev · by visibility.cloud — 2026-07-31
> Written for the in-house supply-chain platform team — the staff engineer who owns the event spine and refuses to own three document stores.

One thesis: **your purchase order does not care whether it traveled as an X12
850, an EDIFACT ORDERS, or a REST webhook — those are dialects, and the
compile target for all three is the same CBV `bizTransaction` reference on
the same EPCIS 2.0 event.**

## The claim, stated as an engineer would state it

A purchase order is a noun in your business. On the wire it has at least
three costumes: a 4010 850 from the retail account that still runs a VAN, an
EDIFACT ORDERS from the European distributor, and a JSON body from the
commerce platform's webhook. Most stacks respond by building three ingest
paths into three tables, then a reconciliation layer to convince themselves
the three tables describe one world.

The standard already refused that design. CBV 2.0 §8.5 defines
`bizTransactionList` as the field that *populates the "why" dimension* of an
event — and defines it on **all** EPCIS event types. The vocabulary of §7.3
gives the values that go in it: `po`, `desadv`, `inv`, `recadv`, and the
rest of a deliberately short list written to be an EDI catalog, not a
metaphor for one. The document is not the record. The document is context
**on** the record.

## The compile target is pinned, not asserted

The proof artifact for this post is not prose; it is a file you can hash.
The official EPCIS 2.0 JSON-LD context — vendored and pinned at sha256
`5056c65f991425b1d3a35e35edf4f7d0c7ff56cf688c2912b930f93494713737`
(retrieved 2026-07-19 from ref.gs1.org, per the family's
[pins discipline](https://epcis.dev/conformance/)) — carries the
business-transaction type sub-context verbatim:

```json
"desadv": "cbv:BTT-desadv",
"inv":    "cbv:BTT-inv",
"po":     "cbv:BTT-po",
"recadv": "cbv:BTT-recadv"
```

Those four are the core of the cycle — order, despatch advice, invoice,
receiving advice — and the same pinned sub-context enumerates the rest of
the vocabulary (`bol`, `cert`, `pedigree`, `poc`, `prodorder`, `rma`,
`testprd`, `testres`, `upevt`). The
[close reading of that enumeration](/blog/the-standard-already-named-your-paperwork/)
is its own post. What matters here: the target vocabulary is small, closed,
and owned by the standard — not by transactions.dev, and not by you.

## One purchase order, three arrivals, one reference

Here is the figure that makes the thesis concrete. The same order,
PO-8812, issued by a buyer whose GLN is 0724142000024's parent party
0724142000017, arrives three ways:

```text
X12 856 (the ASN citing the order)   PRF*PO-8812
EDIFACT / EANCOM                     RFF+ON:PO-8812
biztx-canonical JSON (API-native)    { "kind": "po", "value": "PO-8812" }
```

All three compile to one and the same entry on the emitted event:

```json
"bizTransactionList": [
  {
    "type": "po",
    "bizTransaction": "urn:epcglobal:cbv:bt:0724142000017:PO-8812"
  }
]
```

That identifier shape is CBV 2.0 §8.5's own URN scheme —
`urn:epcglobal:cbv:bt:{issuerGLN}:{reference}` — scoped by the party that
assigned the number, which is what makes the reference equal across
counterparties without a mapping table. The API-native shape above is not a
sketch: it is the published
[biztx-canonical schema](/blog/from-856-to-epcis-document/)'s `references`
entry, and the X12 path is exercised by the same golden fixture pair, byte
for byte.

## Why the event is the join point

The alternative architecture — a document store beside an event store, with
a nightly job that joins them — fails in a specific, predictable way: the
join key lives in application code, and application code drifts. Putting the
reference **on the event** means every downstream consumer that can parse a
conformant EPCIS document gets the paperwork context for free, because the
field it looks in is defined by the standard it already implements.

The emitted record stays conformant and, where a source document carries
more than the standard models, a superset — the two words travel together
here, always, because a superset that stops validating against the pinned
official schema is just a private format with a standards story. Every event
this pipeline emits validates against the pinned EPCIS 2.0 JSON schema
(sha256 `0f46ff69…`) before it leaves the tool; the projection down to the
plain conformant document is lossy in one direction only.

## What each site in the family does with the noun

- [epcis.dev](https://epcis.dev/business-transactions-in-epcis/) is the
  event spine: capture, validate, hash, translate. It treats
  `bizTransactionList` as what it is — a core field.
- **transactions.dev** — this one — is the compiler: `parse` takes the
  dialect (X12, EDIFACT, canonical JSON), `join` emits the conformant
  events with the references, parties, and item grain already placed.
- [barcoding.dev](https://barcoding.dev) is the identifier layer: the
  GTINs, GLNs, and SSCCs that make the joins deterministic instead of
  fuzzy.
- [visibility.cloud](https://visibility.cloud/asn-po-context-in-traces) is
  the executive twin of this post: the same architecture, read side out,
  in plainer language.

## Where this goes next

The worked end-to-end of one document class — a full ASN in, a validated
event skeleton out, every byte accounted for — is
[the 856 compile post](/blog/from-856-to-epcis-document/). The naming law
that ends the ASN argument is
[the desadv post](/blog/desadv-is-the-asn/). And the spec's own answer to
"which events can carry the reference" — all of them — is
[the §8.5 post](/blog/the-why-dimension-rides-on-every-event/).

If the thesis matches a problem you own — three dialects on the wire, one
record you have to defend — the door is [get access](/get-access/): say
what you compile today, and the onboarding flow takes it from there.

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