JSON-LD voor digitale productpaspoorten (en waar EPCIS 2.0 in past)

Een DPP is alleen nuttig voor machines als hij machineleesbaar is. Deze gids laat de echte JSON-LD zien die een qr3-paspoort via de live resolver beschikbaar stelt, hoe één URL via content negotiation zowel mensen als machines bedient, en waar de aanvullende EPCIS 2.0-eventstandaard in past.

door QR3 Redaktion

JSON-LD voor digitale productpaspoorten (en waar EPCIS 2.0 in past)

Een digitaal productpaspoort is bedoeld om gelezen te worden door mensen én door machines: het inname-systeem van een recycler, een douane-API, een marktplaats-crawler, het script van een duurzaamheidsauditor. Een HTML-pagina die alleen voor mensen geschikt is, volstaat niet. Het paspoort moet machineleesbaar zijn — een gestructureerde payload die een programma kan parsen, koppelen en verwerken zonder te scrapen.

Deze gids is bedoeld voor ontwikkelaars die de voor de hand liggende vervolgvraag stellen: zodra ik een DPP heb, hoe leest een machine die dan daadwerkelijk? Het antwoord voor qr3 is JSON-LD via de openbare resolver. We laten de echte response zien, leggen uit hoe dezelfde URL zowel mensen als machines bedient, en plaatsen vervolgens EPCIS 2.0 — de aanvullende GS1-eventstandaard — in context.

Wat machineleesbaarheid betekent voor een DPP

Machineleesbaar is meer dan "geeft JSON terug". Voor een productpaspoort betekent het drie dingen:

  • Gestructureerd — velden die een parser kan adresseren (gtin, name, …), geen proza om te scrapen.
  • Getypeerd en gekoppeld — termen verankerd aan gedeelde vocabulaires zodat Product voor iedereen hetzelfde betekent. Dat is de Linked Data in JSON-LD.
  • Stabiel op te halen — één duurzame URL per item die een script gedurende de volledige levensduur van het product kan GET-ten.

JSON-LD (JSON for Linking Data) levert alle drie. Het is gewone JSON plus een @context die elke key koppelt aan een term in een openbaar vocabulaire — hier schema.org en het GS1 Web Vocabulary. Een crawler die schema.org al begrijpt, begrijpt het paspoort zonder enige maatwerkintegratie.

De DPP als JSON-LD (echte curl + geverifieerde response)

Elk qr3-paspoort wordt opgelost op een GS1 Digital Link-URL: https://qr3.app/dpp/{gtin}/{serial}. Voeg ?format=jsonld toe om de Linked-Data-weergave op te vragen. Tegen de live batterijdemo:

curl -s "https://qr3.app/dpp/04019999999902/DEMO-BAT-01?format=jsonld"

geeft terug:

{
  "@context": ["https://schema.org", "https://gs1.org/voc/"],
  "@type": "Product",
  "gtin": "04019999999902",
  "name": "EcoMax 5000 (Demo)"
}

Drie dingen om op te merken:

  • @context is een array van twee vocabulaires — schema.org voor het algemene web en gs1.org/voc/ voor de producttermen van GS1. Keys worden tegen beide opgelost.
  • @type: "Product" vertelt elke Linked-Data-consument precies wat voor soort entiteit dit is.
  • De waarden (gtin, name) zijn echt en live — dit is de werkelijke payload, geen mock.

Dat is precies het punt: het script van een recycler heeft geen qr3-specifieke client nodig. Het doet een HTTP GET, parst JSON-LD die het al begrijpt, en leest de GTIN en productnaam er rechtstreeks van af.

Eén URL, twee doelgroepen: content negotiation

Dezelfde https://qr3.app/dpp/{gtin}/{serial}-URL bedient zowel een mensvriendelijk HTML-paspoort als de machineweergave — de server beslist wat hij teruggeeft op basis van wat de aanroeper vraagt. Twee manieren om te vragen:

Wat je wilt Query-parameter Of Accept-header
Menselijke HTML-pagina (standaard) Accept: text/html
JSON-LD (Linked Data) ?format=jsonld Accept: application/ld+json
Platte JSON ?format=json
Linkset (gerelateerde resources) ?format=linkset
DCAT-AP (datasetmetadata) ?format=dcat-ap

Een telefooncamera die de QR-code opent, komt dus uit op het leesbare HTML-paspoort, terwijl een script dezelfde identieke URL om application/ld+json vraagt en gestructureerde data krijgt:

# Machineweergave via header-negotiation — zelfde URL, geen query string
curl -s -H "Accept: application/ld+json" \
  "https://qr3.app/dpp/04019999999902/DEMO-BAT-01"

Eén identifier, één URL, vele representaties. De GTIN/serial blijft stabiel; de weergave past zich aan de aanroeper aan. Precies dat maakt een DPP tegelijk duurzaam én interoperabel.

Waar EPCIS 2.0 in past (events vs. paspoort)

Een veelgehoorde vervolgvraag: en EPCIS dan — is dat niet de GS1-standaard hiervoor? Belangrijk onderscheid:

  • Een DPP is de statische beschrijving van één productitem — de identiteit, materialen, CO₂-voetafdruk en recycleerbaarheid ervan. Het beantwoordt "wat is dit ding?" De JSON-LD hierboven is die momentopname.
  • EPCIS 2.0 is de GS1-standaard voor supply-chain-events — de zichtbaarheidsdata van wat er is gebeurd, waar, wanneer en waarom: een item werd in gebruik genomen, verzonden, ontvangen, gerecycled. Het beantwoordt "wat is er met dit ding gebeurd, en waar is het?"

Ze zijn aanvullend, niet concurrerend. Het paspoort vertelt je dat het product een 5,2 kWh-batterij is met 35% gerecycled materiaal; een EPCIS-eventspoor zou je vertellen dat hij op een bepaalde datum in Hamburg is gefabriceerd, via een distributiecentrum is verzonden en bij een recycler is aangekomen. EPCIS 2.0 zelf is JSON/JSON-LD-vriendelijk, dus beide delen dezelfde Linked-Data-wereldvisie en dezelfde GS1-identifiers (GTIN + serial) als koppelsleutel.

qr3-scope (wees precies): qr3 levert de DPP als JSON-LD — dat is wat deze post demonstreert. qr3 biedt geen EPCIS-eventregistratie of EPCIS-endpoints. Beschouw EPCIS 2.0 hier als de conceptuele, aanvullende standaard die je naast een DPP zou inzetten voor volledige supply-chain-traceerbaarheid, niet als een qr3-functie.

Het mentale model is dus: de DPP (qr3, JSON-LD) is het identiteitsblad van het product; EPCIS 2.0 (afzonderlijk systeem) is het reislogboek ervan. Dezelfde identifiers, twee beantwoorde vragen.

Een DPP genereren die JSON-LD beschikbaar stelt

Je hoeft niets bijzonders te doen om JSON-LD "in te schakelen" — maak het paspoort aan en de resolver serveert elke representatie automatisch:

import { QR3 } from "@qr3/sdk";

const client = new QR3({ apiKey: process.env.QR3_API_KEY! });

const passport = await client.dpp.create({
  gtin: "04019999999902",
  serial: "SN-00012345",
  product_name: "PowerCell 5 kWh LFP",
  manufacturer: "ExampleTech GmbH",
  origin_country: "DE",
  category: "battery",
  market_countries: ["DE", "FR", "AT"],
  status: "live",
  battery_data: {
    capacity_kwh: 5,
    carbon_footprint_kg: 62,
    recycled_content_pct: 12,
    recyclability_pct: 95,
  },
});

// The passport now resolves at https://qr3.app/dpp/04019999999902/SN-00012345
// Humans get HTML; machines append ?format=jsonld (or send Accept: application/ld+json).
console.log(passport.qr.svg); // QR encodes the GS1 Digital Link to the resolver

Eenmaal aangemaakt beantwoordt de URL van het item meteen beide doelgroepen — geen extra publicatiestap voor de machineweergave.

FAQ

Waarom JSON-LD en niet platte JSON? Platte JSON is gestructureerd maar niet zelfbeschrijvend: een consument moet jouw veldnamen leren kennen. JSON-LD voegt @context toe en koppelt elke key aan schema.org-/GS1-termen, zodat elke Linked-Data-consument het begrijpt zonder maatwerkintegratie. Als je alleen snel iets wilt uitlezen, is ?format=json nog steeds beschikbaar.

Implementeert qr3 EPCIS 2.0? Nee. qr3 levert de DPP als JSON-LD. EPCIS 2.0 is de afzonderlijke, aanvullende GS1-standaard voor supply-chain-events; die zou je ernaast draaien, gekoppeld via de gedeelde GTIN + serial.

Hoe krijg ik de machineweergave? Voeg ?format=jsonld toe aan de resolver-URL, of stuur Accept: application/ld+json. Beide geven dezelfde Linked-Data-payload terug.

Is de @context stabiel? Hij pint schema.org plus het GS1 Web Vocabulary (gs1.org/voc/) vast — beide openbare, geversioneerde vocabulaires, zodat consumenten kunnen vertrouwen op de betekenis van de termen.

Bronnen

Start gratis en maak een DPP die JSON-LD beschikbaar stelt: app.qr3.app/sign-up