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:
- Connected integration — Centra, Shopify, Akeneo, inriver, commercetools, Magento, WooCommerce, Delogue PLM, TrusTrace, Eon, Avery Dennison atma.io, generic Custom-REST. See Integrations.
- Webhook — your system pushes a signed POST when a product changes. We verify the HMAC and apply the same conflict policy.
- Bulk XLSX import — operator drops a spreadsheet with mapped columns. Used during onboarding and for tail-product backfills.
- CSV/URL import — point us at an HTTPS-served CSV; we re-fetch on a schedule.
- 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 newdpp_revisionsrow is created instatus = 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
- Integrations → Akeneo — full setup walk-through with scope-limitation
- Locale — multi-language ingest + content negotiation
- API → Resolve — the public DPP endpoint
- Compliance — ESPR / AGEC / EN 18216-18223 / ISO 3758 mapping
- Security — vault, scopes, deletion, indexing