---
title: "DPP Resolution: How We Wired It Up"
description: "How OpenEPCIS combined GS1 Digital Link, the IETF linkset format and content negotiation into one DPP resolution flow"
canonical_url: "https://openepcis.io/docs/digital-product-passport/dpp-resolution-flow"
last_updated: "2026-07-02T20:31:55.310Z"
---

## What this page is

A walkthrough of **one way** to take a scanned QR code on a product through to a typed DPP response — the way we did it with GS1 standards. It's not a finished cross-sector product offering and it's not the canonical flow for every regulator and every customer. It's a worked example that exercises the standard primitives in a single path, so a developer or compliance reviewer can see how the pieces fit together.

The standards that show up below — GS1 Digital Link, the GS1 Conformant Resolver discovery contract, IETF `application/linkset+json` (RFC 9264), HTTP content negotiation, and ESPR Article 9 access tiers — are all published. The opinions in between are ours, and other implementations make different ones.

## The flow at a glance

<diagram-image alt="From data carrier through the GS1 resolver to a tier-gated DPP response" src="/diagrams/dpp-resolution-flow">



</diagram-image>

## Walking it through with one example

The example below uses a serialised timber product — chosen because timber under EUDR exercises the access-tier surface (a customs officer needs more detail than a consumer). The same primitives apply when the product is a battery, a garment, a smartphone or a frying pan; only the linkset entries and the JSON-LD payloads change.

### 1 — The Digital Link URI on the carrier

The QR code carries a GS1 Digital Link URI:

```text
https://id.gs1.org/01/09521234000020/21/LOG-2025-001
        └────┬───┘ └──────┬─────┘ └──────┬─────┘
          Base       GTIN (AI 01)   Serial (AI 21)
```

Application Identifiers (`01`, `21`, …) are the same primitives GS1 has used in barcodes for decades. Encoding them in a URL means the same identifier is scannable by a phone camera, queryable by a server, and visible in a browser bar.

### 2 — Resolver lookup

The resolver matches the GTIN against its registry and returns an **application/linkset+json** document (IETF RFC 9264). One object per `anchor`, GS1 link relations as full-IRI keys, link descriptors as values. The discovery contract that lets downstream registries find and validate the deployment is the GS1 Conformant Resolver standard — see [Resolver Setup](/docs/digital-product-passport/resolver-setup) for the full shape and the hosting choices we considered.

### 3 — Content negotiation

The same Digital Link URL serves different representations depending on the `Accept` header. A consumer's phone browser sends `text/html` and lands on a passport web page. A downstream system asks for `application/ld+json` and gets a typed JSON-LD record. RDF tooling asks for `text/turtle`. This is plain HTTP content negotiation, not anything GS1-specific:

<table>
<thead>
  <tr>
    <th>
      Accept header
    </th>
    
    <th>
      Response
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        text/html
      </code>
    </td>
    
    <td>
      Consumer-facing passport page
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        application/ld+json
      </code>
    </td>
    
    <td>
      JSON-LD record
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        application/json
      </code>
    </td>
    
    <td>
      Plain JSON
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text/turtle
      </code>
    </td>
    
    <td>
      RDF / Turtle
    </td>
  </tr>
</tbody>
</table>

### 4 — `linkType` for facet selection

Layered on top of `Accept`, the `?linkType=` query parameter requests a specific facet of the passport. Per the GS1 Digital Link spec the value is the **bare** relation name (the compact `gs1:…` form only appears as keys inside the linkset JSON itself).

The list below is the relations our resolver auto-derives today; a deployment can extend it with sector-specific relations as needed.

<table>
<thead>
  <tr>
    <th>
      <code>
        ?linkType=
      </code>
    </th>
    
    <th>
      What it returns
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        pip
      </code>
    </td>
    
    <td>
      Product Information Page (default)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        epcis
      </code>
    </td>
    
    <td>
      EPCIS event history
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        certificationInfo
      </code>
    </td>
    
    <td>
      Certificates and declarations
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        safetyInfo
      </code>
    </td>
    
    <td>
      Safety data sheet
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        recipeInfo
      </code>
    </td>
    
    <td>
      Composition / BOM
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        serviceInfo
      </code>
    </td>
    
    <td>
      Service and repair
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        productSustainabilityInfo
      </code>
    </td>
    
    <td>
      Carbon footprint, recycling
    </td>
  </tr>
</tbody>
</table>

### 5 — Access tier (ESPR Article 9)

ESPR Article 9 defines three access tiers for DPP data. The resolver enforces them at the request boundary:

<diagram-image alt="How a DPP endpoint decides what to return per ESPR access tier" src="/diagrams/dpp-access-tier-decision">



</diagram-image>

<table>
<thead>
  <tr>
    <th>
      Tier
    </th>
    
    <th>
      Who can read it
    </th>
    
    <th>
      Examples
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <strong>
        Public
      </strong>
    </td>
    
    <td>
      Anyone
    </td>
    
    <td>
      Product name, manufacturer, recycling instructions, headline specs
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        AuthorizedOnly
      </strong>
    </td>
    
    <td>
      Market surveillance, customs, accredited recyclers
    </td>
    
    <td>
      Test reports, compliance dossiers, detailed supply chain
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Restricted
      </strong>
    </td>
    
    <td>
      Named partners under agreement
    </td>
    
    <td>
      Trade secrets, proprietary formulations, full BOM
    </td>
  </tr>
</tbody>
</table>

In our implementation the Authorized and Restricted tiers reuse the same identity layer that gates the EPCIS REST surface — a Keycloak-issued credential, a capability token, or (where we've wired it up) a Verifiable Credential presented via OID4VP. See [Architecture → Wallet-agnostic Verifiable Credentials](/docs/platform-overview/architecture#wallet-agnostic-verifiable-credentials-oid4vc).

## Instance URIs vs vocabulary URIs

The URIs that **identify a specific product** and the URIs that **define what a property means** are distinct, and confusing them is a common early mistake:

- **Instance URI** — `https://id.gs1.org/01/09521234000020/21/LOG-2025-001` resolves to this specific timber log's record.
- **Vocabulary URI** — `https://ref.openepcis.io/extensions/eu/eudr/commodityType` is a *definition* of the `commodityType` term and resolves to documentation.

In a JSON-LD document the `@id` is an instance URI; predicates (`battery:stateOfHealth`, `eudr:commodityType`, …) expand to vocabulary URIs through the `@context`.

## What this walkthrough is not

A few things this page deliberately doesn't claim:

- It isn't a finished product offering. We've built the resolution mechanism and exercised it; the per-sector DPP credentials and the regulator-side acceptance criteria still depend on the underlying regulation landing (ESPR delegated acts, EU Central DPP Registry, sector EN standards). Status notes live on the per-domain implementation pages.
- It isn't the only valid resolution flow. Other implementations put the resolver on a brand-owned domain, redirect rather than serve, gate everything behind authentication, fall back to a static page, or short-circuit content negotiation entirely. Each makes different trade-offs.
- It isn't sector-specific. The primitives — Digital Link URI, linkset, content negotiation, linkType, access tier — are sector-neutral. The per-sector work is which fields go in the JSON-LD payload, not how the URL gets resolved.

## Next steps

- [Resolver Setup Guide](/docs/digital-product-passport/resolver-setup) — hosting options and the linkset JSON shape.
- [Battery DPP Implementation](/docs/digital-product-passport/battery-dpp/implementation-guide), [EUDR Implementation](/docs/digital-product-passport/eudr/implementation-guide), [Textile DPP](/docs/digital-product-passport/textile), [Electronics DPP](/docs/digital-product-passport/electronics) — per-sector linksets and event types.
- [Architecture → Wallet-agnostic Verifiable Credentials](/docs/platform-overview/architecture#wallet-agnostic-verifiable-credentials-oid4vc) — how access-tier enforcement plugs into the OID4VC layer when a presented credential is part of the request.
