DPP Agent docs

DPP Agent — platform overview

DPP Agent is a Digital Product Passport runtime built around the EU ESPR (Ecodesign for Sustainable Products Regulation, EU 2024/1781) and the CEN JTC 24 standards (EN 18216 through EN 18223). A DPP is a persistent, machine-readable record of a product's identity, composition, traceability, compliance, and end-of-life routing, served at a stable URL that survives the product itself.

This page is the platform tour. If you came here to set up your brand, skip to Integrations → Akeneo.

What ships in a DPP

Every DPP carries the following data domains, mapped to canonical ESPR field IDs (espr.pid.*, espr.mat.*, etc.):

  • Product identification — GTIN, model number, brand, colour, size
  • Composition — material breakdown by fibre / alloy / chemistry
  • Hazardous substances — REACH / SVHC declarations
  • Traceability — per-stage supply chain (country, tier, activity, year)
  • Care instructions — ISO 3758:2012 symbol set + free text
  • Durability + circularity — recyclability %, recycled content %, repair availability
  • Environmental footprint — kgCO₂e, water consumption, methodology reference
  • Certifications — GOTS, OEKO-TEX, Cradle to Cradle, OCS, GRS, etc., with issuer + scope + validity
  • Compliance — DoC URL, technical-doc URL, EU Registry ID

Free-text fields stay localisable; structured fields stay structured. See Locale → Ingest model for how multi-language data is captured and resolved.

How a DPP is served

Every DPP has a single canonical URL of the form

https://{brand-slug}.dpp.dppagent.com/01/{GTIN-14}[/10/{batch}][/21/{serial}]

This is a GS1 Digital Link Resolver v1.4 path. Content negotiation on the Accept header determines the representation:

Header Response
text/html Branded DPP page rendered with the tenant's theme
application/ld+json JSON-LD payload following ESPR + schema.org Product vocabulary
application/json Compact JSON representation of dpp_data
?linkType=all Catalog of every linkType applicable to this DPP
?linkType=gs1:digitalProductPassport The DPP itself (default — gs1:productSustainabilityInfo accepted as legacy alias)

JSON probes and HTML browsers see the same record. Search engines and LLM crawlers are blocked by default per the Indexing policy.

Lifecycle and HTTP semantics

Each DPP row has a dpp_status that controls how the URL resolves:

Status HTTP Caller behaviour
draft 404 (JSON) / preview HTML Not publicly resolvable. Browsers see a watermarked preview so on-shelf testing works without forcing operators to manage flags.
active 200 Standard public DPP
withdrawn 410 with branded page Public resolution paused — e.g., recall, reformulation
archived 410 with branded page Permanently retired from public resolution (record retained for audit)
replaced 200, with link to successor New revision exists; consumer redirected via linkType catalog
recalled 410, recall notice Safety recall — page warns + links to manufacturer's recall flow

Status transitions are auditable. A previously-published DPP can be withdrawn or archived but never hard-deleted (regulatory record requirement under EN 18223 §4.1.2). Drafts have no public history and can be hard-deleted from the admin if needed.

Data model

The runtime stores one row per identifier in dpp_runtime:

dpp_runtime
├── id                       UUID                       (primary key)
├── tenant_id                UUID → tenants
├── passport_id              text                       (canonical URL)
├── gtin                     text                       (GS1 canonical 14-digit)
├── batch, serial, cpv       text                       (per granularity)
├── granularity              enum: model | batch | item
├── category                 text                       (textile / battery / electronics / …)
├── dpp_status               enum (see lifecycle table)
├── dpp_data                 jsonb                      (canonical field map)
├── eu_registry_id           text                       (EU Digital Product Passport Registry id)
├── last_updated, created_at timestamptz

dpp_data is the only place where field values live. Keys follow the canonical schema defined in data/dppSchemas.ts. Values are flat strings, numbers, or structured arrays depending on the field. Multi-locale values nest as { "<bcp47>": "<value>" } objects — see Locale.

How data gets in

Five ingestion paths, all converging on a single import pipeline that enforces the same conflict policy:

  1. Connected integration — Centra, Shopify, Akeneo, inriver, commercetools, Magento, WooCommerce, Delogue PLM, TrusTrace, Eon, Avery Dennison atma.io, generic Custom-REST. See Integrations.
  2. Webhook — your system pushes a signed POST when a product changes. We verify the HMAC and apply the same conflict policy.
  3. Bulk XLSX import — operator drops a spreadsheet with mapped columns. Used during onboarding and for tail-product backfills.
  4. CSV/URL import — point us at an HTTPS-served CSV; we re-fetch on a schedule.
  5. Google Sheets — read-only adapter for brands that operate their compliance docs in Sheets.

Manual create is for demos and single-edge-case rows. It does NOT seed fake values; if you scaffold a row by hand you start from an empty dpp_data and either type values, paste a brand product URL and accept AI-Suggest proposals (with explicit source citations per field), or import structured data via one of the other paths. See the Create DPP modal in the admin UI.

Conflict policy on sync

Sync always RESPECTS what's already in the row:

  • dpp_status = draft — sync overwrites freely. Drafts are expected to churn while the brand is preparing the DPP.
  • dpp_status = active — sync NEVER silently overwrites. If the incoming value differs from the live one, a new dpp_revisions row is created in status = pending. The brand's admin reviews the diff field-by-field and promotes the revision before consumers see anything change.
  • dpp_status = withdrawn / archived / recalled — sync ignores. The row is frozen by design.

This is why a sync from your PIM can run hourly without forking your compliance team's published DPPs.

Tenants, accounts, and tiers

A tenant is a brand. One tenant = one slug, one DPP URL prefix, one theme. An account is the customer paying the bill — an account can hold multiple tenants (a brand house with three labels, a marketplace operating DPPs on behalf of sellers, etc.).

Two tiers govern hosting:

  • Light tier — DPPs rendered by DPP Agent runtime under {slug}.dpp.dppagent.com. Lowest-friction onboarding.
  • Custom tier — DPPs also pushed to the brand's Blippa account so the public URL can live under {brand}.com/dpp/… or a fully white-labelled domain. Used by brands with their own consumer app or marketing requirements.

Members on a tenant can hold staff, editor, viewer roles, with per-action permissions documented at /docs/site/security/#roles.

Where to go next