UNTP and EN 18222 interop
No region is the universal envelope. The gateway renders the neutral core in foreign protocol shapes — a protocol is a render profile, not a fork — and imports them back with deterministic identity. Adding a protocol adds a render profile; the core never grows a region’s fields.
The UNTP binding
Section titled “The UNTP binding”Render (core → UNTP)
Section titled “Render (core → UNTP)”GET /untp/product/{id}?freshness= returns the verifiable-credential triad:
- the DigitalProductPassport VC,
- the DigitalConformityCredentials (profile bindings + inspection stamps),
- a link-resolver entry anchored at the log head,
plus the verdict over the evidence. Recorded against the reference deployment:
$ curl -s -G 'http://127.0.0.1:8395/untp/product/urn%3Aunidpp%3Apassport%3Apilot-e8-j000842' \ | jq '{source: .rendering.source, outcome: .verdict.outcome, signatures_verified: .verdict.coverage.signatures.verified}'{ "source": "issuer", "outcome": "pass", "signatures_verified": 5}The five signatures are the passport’s five lifecycle events, verified against the issuer’s published anchors during the render.
Identifier mapping: core cpid: identifiers map to https://unidpp.org/id/
URIs; the GS1 family maps to https://gs1.org/voc/ with (01)/(10)/(21)
application identifiers. The render names its profile
(urn:unidpp:profile:render:untp).
Ingest (UNTP → core)
Section titled “Ingest (UNTP → core)”POST /untp/ingest accepts a UNTP passport VC (bare or as a triad) and mints
a core passport with a deterministic identity — idempotent per subject:
submitting the same VC twice yields one core passport, not two. Imported
documents carry an empty event log (their events live in the source regime)
and a receipt recording the origin. Render and ingest are inverse
projections.
The EN 18222 binding
Section titled “The EN 18222 binding”GET /en18222/v1/dppsByProductId/{gtin}?representation=full|compressed —
the EN 18222 REST shape, default compressed per the EN. Recorded:
$ curl -s 'http://127.0.0.1:8395/en18222/v1/dppsByProductId/4006381333931?representation=full' \ | jq '.dppStatus'"active"- full: the element tree, string-printed values;
- compressed: collection-keyed, native JSON values.
The wire field set is mirrored from the freeDPP live-endpoint artifacts (the
conformance corpus keeps both representations as fixtures) — an EN 18222
client sees what it expects, including the frozen-wire rule: no as_of
member on the EN 18222 body (the x-as-of header still carries it).
Semantics sources
Section titled “Semantics sources”The renderings are ports, not re-derivations: the UNTP adapter’s semantics
come from the Python reference adapters (unidpp-py), and the EN 18222 wire
from the freeDPP artifacts. The gateway’s discovery document states both
provenances. What that buys an operator: when a question arises — is this
field part of the compressed representation? does the triad include the
resolver entry? — the answer lives in the reference implementation and the
conformance corpus, not in prose.
Degradation and failure behavior
Section titled “Degradation and failure behavior”- No upstream, or upstream unreachable → fixtures serve, the render metadata
names the source (
fixtures). - Unknown and deliberately unresolvable ids → identical 404 bytes (I12).
?freshness=on the UNTP render bounds the evidence freshness window the verdict applies.
Which binding do I expose?
Section titled “Which binding do I expose?”The gateway serves both simultaneously; there is no either/or. A deployment facing EU regulation serves the EN 18222 binding; one facing UNTP counterparts serves the triad; both come from the same core passports, signed by the same keyrings, anchored in the same log. The choice of what to tunnel to the public internet is a per-deployment exposure decision (see security posture).