# 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](https://ref.gs1.org/standards/epcis/) 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 behavior 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 behavior every
door has.

**Proof, not adjectives.** `translate`, `validate` and `hash` pass their conformance suites
against GS1's normative artifacts, 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](https://epcis.dev/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, and the row it writes is yours.
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](/get-a-key?segment=integration)**

*The promise, in full: One email when your key is ready — and follow up about it from there. We
don’t sell your address or hand it to advertisers. If we stop working on this, we say so rather
than go quiet.*

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 are in the article this
one sits under:

**→ [Build an EPCIS 2.0 repository — the full write-up](https://epcis.dev/build-an-epcis-repository)**

---
---

---

**Proof, not adjectives.** This build could not verify the gateway's test suite green, so no sentence on this page claims a passing run — the last verified run is recorded in the repository's own CI, not here. Live on this origin, no key: POST /translate, /validate, /hash. No conformance attestation has ever been issued. The dated ledger is /what-ships-today/.
