Docs

Validate & hash

Two calculators, one discipline. /validate answers a verdict against the pinned official GS1 EPCIS 2.0.1 JSON schema — the response names the artefact and its sha256, so two parties disagreeing about validity are disagreeing about bytes, not versions. /hash computes the CBV 2.0 §8.9 standardized event hash — identity is computed from the event's content, never assigned by a database.

POST /validate

contractvalue
Method, pathPOST https://epcis.dev/validate
Authnone — no key, no account
Price classfree
Requestapplication/json or application/ld+json: an EPCISDocument or a bare EPCIS event object
200 response{ valid, schema: { artefact, version, sha256 }, errors: [{ path, keyword, message }] }
Response headersGS1-EPCIS-Version, GS1-CBV-Version, GS1-Extensions
CLI twinnpx epcis.dev validate <file.json> [--project]
Library twinimport { validateEpcis, getEpcisValidator, getQueryValidator, project } from "epcis.dev"

A negative verdict is a 200 with valid: false and per-path errors — the calculator worked; the document failed. The typed refusals below are reserved for requests the door cannot judge at all.

statustypemeaning
400epcisException:ValidationExceptionmalformed JSON
413epcisException:CaptureLimitExceededExceptionpayload exceeds the file-size limit
415epcisException:UnsupportedMediaTypeExceptionthis door accepts JSON; POST XML to /translate

POST /hash

contractvalue
Method, pathPOST https://epcis.dev/hash
Authnone — no key, no account
Price classfree
Requestapplication/json or application/ld+json: a single event, an array of events, or an EPCISDocument with epcisBody.eventList
200 response{ algorithm, count, hashes: ["ni:///sha-256;…?ver=CBV2.0"] }
Response headersGS1-EPCIS-Version, GS1-CBV-Version, GS1-Extensions
CLI twinnpx epcis.dev hash <file.json>
Library twinimport { eventHash, canonicalJson, preHashString } from "epcis.dev"
Typed refusals400 ValidationException (malformed JSON, or no EPCIS events found) · 413 CaptureLimitExceededException · 415 UnsupportedMediaTypeException

The §8.9 algorithm itself excludes eventID, recordTime and errorDeclaration, so a gateway filling those in does not change the hash. Send events as they are — do not pre-strip anything.

Proof — both doors, one fixture

Executed against production with the shipped fixture golden-corpus/valid-standard/object-event-shipping.json:

$ curl -sS -X POST https://epcis.dev/validate \
    -H 'content-type: application/json' \
    --data-binary @object-event-shipping.json
{
  "valid": true,
  "schema": {
    "artefact": "epcis-json-schema.json",
    "version": "2.0.1",
    "sha256": "0f46ff694efffd8d8ce840a33dfde84228add11b516b8b258f3200740ae210af"
  },
  "errors": []
}

$ curl -sS -X POST https://epcis.dev/hash \
    -H 'content-type: application/json' \
    --data-binary @object-event-shipping.json
{
  "algorithm": "CBV 2.0 §8.9 event hash",
  "count": 1,
  "hashes": [
    "ni:///sha-256;e5624abcce4b2fc226743e8891f69c12a07ad508953749d9b9ede6771424f91e?ver=CBV2.0"
  ]
}

The canonicalization trace

The hash is sha-256 over a deterministic pre-hash string — §8.9's canonical ordering of the event's fields with CBV values expanded to their web-URI forms. The library exposes the intermediate steps so you can audit any hash to the byte. The opening of the pre-hash string for the same event, from preHashString(event):

eventType=ObjectEventeventTime=2026-07-19T10:30:00.000Z
eventTimeZoneOffset=+00:00epcListepc=https://id.gs1.org/01/1061414107346
4/21/2018action=OBSERVEbizStep=https://ref.gs1.org/cbv/BizStep-shipping…

(One unbroken string on the wire; wrapped here for the page.) Same event, same bytes, same ni URI — on this door, in npx epcis.dev hash, and in any other §8.9 implementation, including the OpenEPCIS vectors.

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.