DPP Agent docs

The resolve endpoint — public DPP API

This page documents the public DPP endpoint, which is implementation-compliant with GS1 Digital Link Resolver specification v1.4 and the CEN JTC 24 EN 18216 §5 content negotiation rules.

Canonical URL pattern

https://{slug}.dpp.dppagent.com/{primary-scheme}/{primary-id}[/{secondary-key}/{secondary-id}]

{slug} is the brand's tenant slug. Custom-tier brands replace {slug}.dpp.dppagent.com with a brand-owned domain (e.g. dpp.example.com) via DNS CNAME — the resolver is the same.

Supported {primary-scheme} values:

Scheme Form Use case
01 GS1 GTIN-14 Apparel, footwear, electronics, food, cosmetics
8004 GS1 GIAI Reusable assets, durable goods
vin ISO 3779 VIN Vehicles
c Container code Containers, packaging
battery EU Battery Reg Batteries
products Brand-internal Catch-all, legacy URLs

Granularity secondary keys (when applicable):

  • /10/{batch} — batch granularity
  • /21/{serial} — item granularity
  • /22/{cpv} — consumer product variant

Examples:

https://twisttango.dpp.dppagent.com/01/07332485858214
https://twisttango.dpp.dppagent.com/01/07332485858214/10/AW26-001
https://twisttango.dpp.dppagent.com/01/07332485858214/10/AW26-001/21/SR-00451

Content negotiation

Accept header drives the representation:

text/html — branded DPP

The default for browsers. Returns the tenant's themed DPP page, rendered with the active template (renderTextileHTML / renderMinimalTechHTML / etc.). Headers:

HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
Content-Language: sv-SE
Vary: Accept-Language
Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800
X-Robots-Tag: noindex, nofollow, noarchive   (unless tenant opts in)

application/ld+json — JSON-LD

GET /01/07332485858214 HTTP/2
Accept: application/ld+json
{
  "@context": [
    "https://schema.org",
    "https://ref.gs1.org/voc/dpp/"
  ],
  "@type": "Product",
  "identifier": "07332485858214",
  "gtin14": "07332485858214",
  "name": "Pro Winter Jacket",
  "brand": { "@type": "Brand", "name": "Example" },
  "additionalProperty": [
    { "@type": "PropertyValue", "name": "espr.mat.fibre_composition", "value": "57% Wool, 43% Recycled Polyester" },
    ...
  ],
  "isPartOf": {
    "@type": "ProductGroup",
    "identifier": "PW-101"
  }
}

Headers identical to the HTML response with Content-Type swapped. Used by structured-data crawlers and by partner systems doing catalogue federation.

application/json — compact DPP

{
  "passport_id":  "https://twisttango.dpp.dppagent.com/01/07332485858214",
  "gtin":         "07332485858214",
  "status":       "active",
  "granularity":  "model",
  "category":     "textile",
  "last_updated": "2026-06-11T07:54:32Z",
  "dpp_data": {
    "espr.pid.product_name": { "en-GB": "Pro Winter Jacket", "sv-SE": "Vinterjacka Pro" },
    "espr.mat.fibre_composition": "57% Wool, 43% Recycled Polyester",
    ...
  }
}

Used by brand-owned client applications. Lightweight and language-aware.

linkType catalogue — GS1 Digital Link §6

?linkType=all returns the catalogue of every applicable resource for this DPP:

GET /01/07332485858214?linkType=all HTTP/2
Accept: application/json
{
  "gtin": "07332485858214",
  "linkset": [
    {
      "linkType": "gs1:digitalProductPassport",
      "href":     "https://twisttango.dpp.dppagent.com/01/07332485858214",
      "title":    "Digital Product Passport",
      "type":     "text/html",
      "default":  true
    },
    {
      "linkType": "gs1:productInstructions",
      "href":     "https://twisttango.dpp.dppagent.com/01/07332485858214#sect-07",
      "title":    "Care instructions",
      "anchor":   "care"
    },
    {
      "linkType": "gs1:hasSafetyDataSheet",
      "href":     "https://brand.example.com/sds/PW-101.pdf",
      "title":    "Safety data sheet"
    },
    {
      "linkType": "gs1:hasCertificationInfo",
      "href":     "https://twisttango.dpp.dppagent.com/01/07332485858214#sect-09",
      "title":    "Certifications"
    }
  ]
}

Individual linkTypes can also be requested directly with a 303 redirect (the GS1 spec's recommended pattern):

GET /01/07332485858214?linkType=gs1:productInstructions HTTP/2

HTTP/2 303 See Other
Location: https://twisttango.dpp.dppagent.com/01/07332485858214#sect-07

Default behaviour (no linkType, or linkType=gs1:digitalProductPassport): serve the DPP itself. gs1:productSustainabilityInfo is accepted as an alias for backwards compatibility with scanners written against the pre-2025 GS1 Web Vocabulary.

Lifecycle responses

dpp_status HTTP Body
draft 404 (JSON) / 200 (HTML preview with watermark) Drafts are not publicly resolvable; HTML clients see a preview to support on-shelf testing
active 200 Standard DPP
replaced 200 Passport, plus Link header pointing to successor
withdrawn 410 Branded HTML "withdrawn" page (or JSON for API)
archived 410 Branded HTML "archived" page
recalled 410 Recall notice with manufacturer recall-flow link

The HTML representation for withdrawn / archived / recalled is on-brand (uses the tenant's theme) so the consumer-facing language is recognisable even when the DPP is no longer being served.

Caching

We cache aggressively at the edge:

  • Active DPPs — Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800. Edge holds the response for 24h; clients refresh hourly.
  • Draft / preview — Cache-Control: no-store, max-age=0.
  • 404 / 410 — short cache (5 min) to absorb scan storms.

The CDN respects Vary: Accept-Language so per-locale variants cache independently.

When a brand publishes a revision the resolver issues a targeted purge against the canonical URL. There's no global TTL flush; only the affected DPP is invalidated.

Rate limits

None applied to public DPP reads. The endpoint is designed to be scannable from QR codes on consumer-facing packaging where sudden traffic spikes (campaign launches, retail events) are expected.

Admin and integration endpoints are rate-limited and require authentication.

Query parameters

Param Values Effect
linkType gs1:pip, gs1:tds, all (+ more) GS1 Digital Link §6 link-type selection. all returns a directory JSON of every linkType the brand has registered for this identifier.
schema cirpass-2 / cirpass When the Accept header asks for JSON, returns the nested CIRPASS-2 object instead of the default ESPR-flat key namespace.
as role-slug (consumer, manufacturer, ...) Section-audience impersonation. Picks which DPP sections the resolver renders. Defaults to consumer when omitted; unknown slugs fall back to consumer. Has no effect for tenants with role_access_enabled = FALSE (the platform default). See Security & privacy → Roles.
preview 1 Render non-public DPP statuses (draft, withdrawn, archived, recalled) with a watermark. Operators only — the link is suggested in the admin UI but the resolver does not require auth (the URLs are unguessable).

?as= whitelist:

consumer · economic-operator · manufacturer · importer · distributor ·
online-marketplace · repairer · refurbisher · recycler · customs-authority ·
market-surveillance · competent-authority

Plus any per-tenant custom roles registered in the role catalogue.

Open-graph and social sharing

The HTML response includes complete OG tags:

<meta property="og:type"        content="product">
<meta property="og:title"       content="Pro Winter Jacket — Example">
<meta property="og:description" content="Digital Product Passport: composition, care, recycling.">
<meta property="og:image"       content="https://cdn.example.com/products/PW-101-hero.jpg">
<meta property="og:url"         content="https://twisttango.dpp.dppagent.com/01/07332485858214">

The image falls back to the hero image, then the brand logo, then a generic placeholder — see the hero image resolution rules in api/v1/resolve.js for the exact walk order.

Error responses

All errors are JSON unless the client sent Accept: text/html, in which case they render as a branded notice page.

{
  "error":  "Primary identifier missing from GS1 GTIN path",
  "path":   "/01/",
  "scheme": "gtin"
}
Code Reason
400 Malformed path or unknown scheme
404 Path well-formed but no DPP matches
410 DPP withdrawn / archived / recalled
503 Backing store temporarily unreachable