Build an EPCIS 2.0 repository

You don't build an EPCIS 2.0 API. You build the part of it that's actually yours.

Someone handed you a ticket that reads "stand up an EPCIS 2.0 capture and query endpoint." It sounds like a week. It is a week — for the part that is specific to your company. The other part, the part that makes it conformant rather than EPCIS-shaped, is a decade of GS1 committee decisions rendered as code, and it is the part that keeps you on the hook long after the ticket closes.

So before you npm init, separate the two. There is a layer that is 90% identical for you, your competitor, and the vendor down the street — the schema, the error contract, the event hash, the storage semantics — and a layer that is yours alone: which of your systems emit events, what your GTIN/GLN keys mean, how a trace answers your operators' actual question. Reinventing the first layer is the classic staff-engineer trap: it feels like real work, it demos fine, and it becomes a permanent tax you pay in Fridays. This article is about taking the first layer as a pinned dependency and spending your sprint on the second.

What "an EPCIS 2.0 API" is, precisely

EPCIS 2.0 is not a database or a product. It is two HTTP interfaces plus the event model that flows across them:

  • A capture interface — you POST an EPCIS document (or a single event) and the repository durably records it. The EPCIS 2.0 standard publishes the official JSON schema and an OpenAPI description of this interface; you do not get to invent the shape.
  • A query interface — you ask "where did EPC X go," "what happened at location Y between two timestamps," "show me every aggregation event for this pallet," and the repository answers over a standardized query grammar.
  • The event model — every event is one of five types (ObjectEvent, AggregationEvent, TransactionEvent, TransformationEvent, AssociationEvent) carrying the dimensions the standard defines: what (the EPCs / quantities), when (event time), where (read point, business location), why (business step, disposition), and how (sensor and other extensions).

"Reinventing the standard" means hand-writing any of that — copying a subset of the schema into your own validators, inventing your own error strings, computing an event hash your own way. Every one of those choices is a place where your repository and your trading partner's repository silently disagree, and the whole point of EPCIS is that they don't.

The eight laws the standard implies but doesn't hand you as code

Here is the gap that turns a one-week ticket into a three-year commitment. The EPCIS 2.0 documents tell you what conformant behaviour is. They do not ship you a repository that enforces it. Between "I read the spec" and "an auditor accepts my endpoint" sit eight laws you have to build and keep building:

  1. *Validate every captured event against GS1's official JSON schema — before it lands.* Not a hand-copied subset that drifts from the published one. The schema is versioned; you pin the exact version and record the digest, or you are validating against a guess.
  2. Return failures as RFC 7807 application/problem+json, carrying the standard's own exception types. When capture rejects a document, the caller must see the error EPCIS names — not a 400 with a string you invented that their client can't branch on.
  3. Compute the CBV 2.0 §8.9 event hash and check it against reference vectors. The event hash is the shared identity of an event across parties. If your hash and your partner's hash disagree for the same event, the event isn't shared — it's disputed.
  4. Store append-only. No identity holds an UPDATE or DELETE grant. An event ledger you can quietly edit is not evidence. Append-only isn't a convention you promise in a README; it's a grant that nobody in the system possesses.
  5. Scope reads minimally — out-of-scope data is absent, not redacted. A caller sees the events their grant covers and has no way to detect the existence of the ones it doesn't. Redaction leaks structure; absence doesn't.
  6. Stamp provenance at the gateway, not from the payload. recordTime, and who captured the event, are asserted by the door — caller-supplied values in those fields are stripped. Provenance a sender can write about itself is not provenance.
  7. Preserve fidelity across the version boundary. If you accept a decade of EPCIS 1.1/1.2 XML, the translation to 2.0 JSON-LD has to be lossless and provably so — a per-job round-trip report, not a hope.
  8. Gate the whole thing in CI against the GS1 test requirements. "It conformed on my laptop in March" is not conformance. The suite runs on every commit, or the pin has already drifted.

Notice what these eight have in common: none of them is your product. All of them are mandatory. This is exactly the shape of thing you take as a dependency rather than staff.

The concrete build: take the interfaces, keep the substrate

The way this repository is built is the recommendation: implement the EPCIS 2.0 capture and query interfaces against GS1's official OpenAPI description, pinned by digest, and enforce the eight laws on every path. The pins live in a PINS.json with sha256 provenance at a named EPCIS version, so "which standard are you conformant to" has a checkable answer instead of a vibe.

# translate · validate · hash — the calculator verbs,
# no account, no gate on compute; the same engine answers on
# this origin at POST /translate, /validate and /hash
npx epcis.dev validate ./event.json
# → conforms  |  RFC 7807 problem+json carrying the EPCIS exception type

npx epcis.dev translate ./legacy-events.xml
# → EPCIS 2.0 JSON-LD  +  a per-job round-trip fidelity report

That is the honest evaluation, and it is the one you should trust least on our say-so: point translate at a real EPCIS file you already have and read the fidelity report yourself. The capture and query interfaces ride the full durable substrate — the same append-only, gateway-stamped, schema-validated laws on every path — so what you evaluate on your own corpus is the behaviour every door has.

Proof, not adjectives. translate, validate and hash pass their conformance suites against GS1's normative artefacts, with no account and no gate on compute; the capture and query interfaces run under the full durable substrate — append-only, gateway-stamped, schema-validated. The calculators answer on this origin — POST /translate, /validate, /hash, no key — and npx epcis.dev runs the full gateway on your bench. The hosted capture spine and issued capture keys are open entries in the dated ledger: What ships today.

What you actually build on top

With the eight laws taken as a dependency, your sprint goes where the value is:

  • The producers. The adapter from your WMS/ERP/line events into conformant EPCIS 2.0 documents — your GTIN and GLN mapping, your business-step vocabulary, your batch/lot semantics. This is genuinely yours and worth your senior time.
  • The questions. The traces and reports your operators need, expressed over the standard query interface. "Reinventing the standard" is a tax; asking better questions of it is your product.
  • The integration key path. How your own systems authenticate to POST events — which is precisely the integration intent below.

The test for whether a line of code belongs to you: would your competitor write the exact same line? If yes, it's the standards layer — pin it. If no, it's your product — build it well.

Why this beats "we'll just implement the spec"

The cost of reinventing the standard is never visible in the first sprint. It shows up in the second implementation — the translator and validator that are 90% the same as everyone else's and 100% yours to maintain, unpinned to a standard that keeps revising, undocumented, load-bearing, and eventually the reason a person can't rotate off the team. Every engineer you keep on the EPCIS committee's homework is a feature you didn't ship, and conformance differentiates your product by exactly zero. Take the layer as a pinned dependency with published provenance, and put the squad back on the part that is actually yours.

FSMA 204 sits under all of this as a de-risking floor — the traceability obligation is often why the build mandate exists — but it is not the reason to do this now, and it is falsifiable in one search, so don't lead your business case on it. The reason to take the standards layer as a dependency this quarter is engineering time on any timeline.

Stand it up

The forward-looking promise on this whole project is a single one — the capture-key list — and it's honest because a real store on this origin backs it: keys are provisioned from the list, in order. If your plan is to POST EPCIS 2.0 events from your own WMS, ERP, or line and you want a key and the schema, tell the door that:

Get a capture key — segment: integration

The promise, in full: Keys are provisioned from this list, in order. One email when yours is ready — one, not a drip campaign. No newsletter, no sequence. If we stop working on this, you get one message saying so and your address is deleted. Either way it is one message.

Prefer not to wait? npx epcis.dev runs the translate · validate · hash verbs on your bench, no account — and the same engine answers on this origin at POST /translate, /validate and /hash. And the full architecture, the eight laws, and the provenance model live on the pillar this article sits under:

Build an EPCIS 2.0 repository — the pillar

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.