The blog · 2026-07-31
bizTransaction is a core field, not a custom extension
Written for ED-1 — the supply-chain ISV / traceability-vendor engineering org — the staff engineer answering "can your product carry our PO numbers?".
One thesis: when a customer asks whether your product can attach their purchase orders, ASNs, and invoices to traceability events, the correct answer is that the standard already reserved the field — and any design that invents a custom extension for it is wrong on the spec's own terms.
The citation, before the argument
CBV 2.0 §7.3 defines the BusinessTransactionTypeID vocabulary. It is a closed, standardized list, and it reads like an EDI catalog because it was written as one: po (purchase order), inv (invoice), bol (bill of lading), prodorder, recadv (receiving advice), and desadv — the despatch advice, with the definition that settles the naming argument in your next architecture review: "Also called an 'Advanced Shipment Notice,' but the value desadv is always used regardless of local nomenclature."
CBV 2.0 §8.5 then places bizTransactionList on all EPCIS event types — ObjectEvent, AggregationEvent, TransactionEvent, TransformationEvent, AssociationEvent. Not a corner of the model. The spine of it.
That is the entire legal basis the transaction layer needs, and it is why transactions.dev exists as a compiler rather than a schema: X12, EDIFACT, and API-native documents in, bizTransaction references and party context out, on core fields every conformant consumer already parses.
The proof artifact is pinned, not quoted
Your review board should not take a blog post's word for a spec claim, so here is where the claim is checkable against pinned artifacts rather than prose. The official EPCIS 2.0 JSON-LD context — vendored and sha256-pinned in the open epcis.dev artifact set, digests published on the conformance page — maps the CBV types directly:
"po": "cbv:BTT-po",
"desadv": "cbv:BTT-desadv",
"inv": "cbv:BTT-inv",
"recadv": "cbv:BTT-recadv"
And the golden corpus carries a ratified-shape fixture, transaction-event-po.json, whose relevant lines are exactly what your product would emit:
"bizTransactionList": [
{
"type": "po",
"bizTransaction": "urn:epc:id:gdti:0614141.06012.1234"
}
],
"sourceList": [
{ "type": "owning_party", "source": "urn:epc:id:pgln:0614141.00001" }
]
Validate that event against the pinned official EPCIS 2.0 JSON schema and it passes. That is the acceptance bar the join verb enforces on everything it emits: superset where a document carries more than the standard models, and conformant always — the two words travel together, because a superset that stops validating is just a fork with better marketing.
The §7.3 table, worked against one real document
Abstract vocabulary tables convince nobody, so here is the closed list doing its job against the golden join corpus's 856, 856-ship-notice-01.edi — the fixture pair reproduced byte-for-byte in the compile post. One ASN carries three of the §7.3 types at once, each from a different segment of the source:
CBV type source in the 856 emitted bizTransaction
desadv BSN*00*SHIP20260730001 urn:epcglobal:cbv:bt:0614141000012:SHIP20260730001
po PRF*PO-8812 (order HL) urn:epcglobal:cbv:bt:0724142000017:PO-8812
bol REF*BM*BOL-991 urn:epcglobal:cbv:bt:0614141000012:BOL-991
Every row is core vocabulary. The identifier scheme is CBV §8.5's own — assigning-party GLN, then the party's reference — so the desadv and bol are scoped by the ship-from GLN and the po by the buyer GLN that issued it, straight from the document's N1 loop. Three business documents, three types, one bizTransactionList, zero extension fields: the vocabulary was sized for exactly this paperwork because it was written from it.
What this means for your product
You ship software to supply-chain customers. Somewhere in your backlog is a ticket shaped like "attach ERP document references to trace records," and two bad designs are competing for it:
- The custom-field design. customerPoNumber in your own namespace. It works until the first conformant consumer downstream — a retailer's system, a regulator's tooling, another vendor — reads your events and sees nothing where the standard told it to look.
- The full-EDI-stack design. Embed a translator, take on trading-partner onboarding, become an EDI vendor with a traceability feature. Your roadmap did not ask for that company.
The compile target is the third design. transactions.dev is a dependency with one contract: documents in, core-field context out. parse gives you lossless canonical JSON; join gives you conformant events with bizTransactionList, sourceList/destinationList, and master-data joins already placed; npx transactions.dev runs the whole thing on your bench, and the MCP door exposes the same verbs to your customers' agents with no second code path. Your product keeps its own event pipeline and its own opinions — it gains the standard's join fields without staffing them.
The worked end-to-end of one document class is in the 856 post; the receiving-side counterpart — recadv, and what happens when the documents and the events disagree — is the reconcile post.
The line for the RFP response
When the question lands in a bid — "can you carry our transaction context on EPCIS events?" — the answer that wins is one sentence long and cites no vendor: purchase orders, despatch advices, invoices, and receiving advices are attached as CBV 2.0 §7.3 business-transaction references on the bizTransactionList field that EPCIS 2.0 defines on every event type, and every emitted event validates against the pinned official schema.
No extension namespace. No proprietary join table. No "our platform's flexible metadata model." The standard already has a field for your purchase order; the only thing missing was the compiler that fills it — and the door that receives what it emits is already open at epcis.dev.
865 words. The access flow is at /get-access/; the family's event door is epcis.dev.