The resolve endpoint — the passport's own address
Every passport answers at its own address. The same address serves the passport page to a person, JSON or JSON-LD to a program, and a linkset of related links. No key is needed. The formats follow EN 18216 and the addressing follows GS1 Digital Link.
Address pattern
https://{slug}.dpp.dppagent.com/{scheme}/{id}[/{qualifier}/{value}…]
{slug} is the brand's tenant slug. A brand with its own verified
domain (for example dpp.example.com, pointed at DPP Agent by DNS)
serves the same paths there, and that domain becomes the passport's
public address.
| Path | Identifier | EN 18219 |
|---|---|---|
/01/{GTIN} |
GS1 GTIN, padded to 14 digits | ID scheme 1 |
/8004/{GIAI} |
GS1 Individual Asset Identifier | ID scheme 1 |
/products/{article} |
The brand's article number | ID scheme 2 |
/battery/{id} |
Battery identifier | ID scheme 2 |
/vin/{VIN} |
Vehicle identification number | ID scheme 2 |
/c/{id} |
Another scheme the brand already runs | ID scheme 2 |
/?.P={model}&.10B={batch}&.S={serial} |
EN IEC 61406-2 Identification Link | ID scheme 2 |
GTIN qualifiers:
/22/{cpv}— consumer product variant/10/{batch}— batch or lot/21/{serial}— serial number
Examples:
https://example.dpp.dppagent.com/01/09506000134352
https://example.dpp.dppagent.com/01/09506000134352/10/AW26-001
https://example.dpp.dppagent.com/01/09506000134352/10/AW26-001/21/SR-00451
Content negotiation
The Accept header picks the form. Every response lists the others
in its Link header (rel="alternate" for JSON and JSON-LD,
rel="linkset" for the linkset) and carries Vary: Accept, Accept-Language.
text/html — the passport page
The default, and what a phone gets after scanning. The brand's page,
rendered on the server, in the best language Accept-Language allows
(Content-Language says which). Passport pages carry X-Robots-Tag: noindex, nofollow, noarchive unless the brand allows indexing.
application/json and application/ld+json
GET /01/09506000134352 HTTP/2
Accept: application/ld+json
{
"@context": ["https://schema.org", "https://dppagent.com/vocab/dpp/v1"],
"@id": "https://example.dpp.dppagent.com/01/09506000134352",
"@type": "DigitalProductPassport",
"dppId": "3f2a9b1c-e0d8-4f8e-b308-d2541886e331",
"productIdentification": {
"uniqueProductIdentifier": "https://example.dpp.dppagent.com/01/09506000134352",
"gtin": "09506000134352",
"cpv": null,
"batch": null,
"serial": null,
"category": "textile"
},
"dppMetadata": {
"digitalProductPassportId": "https://example.dpp.dppagent.com/01/09506000134352",
"granularity": "model",
"dppSchemaVersion": "1.0.0",
"dppStatus": "active",
"lastUpdated": "2026-06-11T07:54:32Z",
"economicOperatorId": "PEPPOL:0007:5560000000",
"facilityId": null,
"linkToPreviousDPP": null,
"backupHost": { "url": "…", "name": "…" }
},
"productData": {
"espr.pid.product_name": "Pro Winter Jacket",
"tex.journey.steps": ["…"]
},
"services": [
{ "type": "support", "label": "Support", "url": "https://example.com/help", "linkType": "gs1:support" }
]
}
application/json returns the same object without @context and
@type. Restricted fields (for example the battery data Article 77(2)
of the Battery Regulation reserves for authorities) are never in the
public response. ?schema=cirpass-2 returns the data in the CIRPASS-2
shape instead.
Links — GS1 Digital Link
?linkType=all returns every link the passport has as an RFC 9264
linkset, with Content-Type: application/linkset+json:
GET /01/09506000134352?linkType=all HTTP/2
{
"linkset": [
{
"anchor": "https://example.dpp.dppagent.com/01/09506000134352",
"itemDescription": "Pro Winter Jacket",
"gs1:dpp": [
{ "href": "https://example.dpp.dppagent.com/01/09506000134352", "title": "Digital Product Passport (ESPR)", "type": "text/html", "hreflang": ["en"], "defaultLinkType": true }
],
"gs1:instructions": [
{ "href": "https://example.dpp.dppagent.com/01/09506000134352#care", "title": "Care & use instructions" }
],
"gs1:certificationInfo": [
{ "href": "https://example.dpp.dppagent.com/01/09506000134352#certifications", "title": "Certifications" }
]
}
]
}
Link types, named as in GS1's registry:
| Link type | Present when |
|---|---|
gs1:dpp |
always; the passport itself (the default link) |
gs1:sustainabilityInfo |
always; an alias of gs1:dpp |
gs1:pip |
the brand has a product page address |
gs1:certificationInfo |
the passport lists certificates |
gs1:traceability |
the passport has supply-chain steps or countries |
gs1:instructions |
the passport has care or use instructions |
gs1:safetyInfo |
the passport has safety information |
gs1:recallStatus |
the passport is recalled |
gs1:epcisRepository |
the passport names an EPCIS endpoint |
service links (gs1:support and others) |
the brand has set up the service |
A single link type, ?linkType=gs1:instructions:
- from a browser,
303 See Otherto the link's target; - with
Accept: application/json, a linkset holding just that link; 404if the passport has no such link.
gs1:dpp (or no linkType) serves the passport itself. An unknown
link type answers 404 with the supported list. Older names
(gs1:digitalProductPassport, gs1:productInstructions, gs1:epcis,
gs1:productSustainabilityInfo) are still accepted.
Lifecycle
dpp_status |
HTTP |
|---|---|
active, replaced |
200 |
recalled |
200, with the recall shown and gs1:recallStatus |
withdrawn, archived |
410: a page explaining it for browsers, { "error": "DPP is no longer publicly resolvable", "status": "…" } for JSON |
draft |
404, unless opened with a preview link |
?preview=1 shows a draft (or a withdrawn passport) with a preview
banner, when the brand allows preview links; otherwise a signed
preview link from the dashboard is needed.
Caching
| Response | Cache-Control |
|---|---|
| active or replaced passport, linkset | public, s-maxage=300, stale-while-revalidate=86400 |
| draft preview, withdrawn, archived | public, s-maxage=10 |
| not found | public, s-maxage=10 |
s-maxage applies to the CDN, which holds a published passport for up
to five minutes and serves the previous copy while it refreshes. A
change to a passport is therefore public within about five minutes.
Rate limits
Reads are free and need no key, but one address gets at most 120
requests a minute; above that the answer is 429 with Retry-After
and a plain-text body. Search-engine crawlers that identify themselves
(Googlebot, Bingbot, Applebot and others) are not counted.
Query parameters
| Param | Values | Effect |
|---|---|---|
linkType |
all, or a link type |
See Links |
schema |
cirpass-2 |
JSON in the CIRPASS-2 shape |
src |
tag, label, web |
Where the code was scanned from; recorded with the scan |
preview |
1 |
Preview of a draft, see above |
Sharing
The HTML page carries Open Graph tags (og:type, og:title,
og:description, og:image, og:url), so a shared passport link
shows the product. The image is the product's hero image, then the
brand logo, then a placeholder.
Errors
Errors are JSON, or a page in the brand's style when the client asked for HTML.
| Code | Reason |
|---|---|
| 400 | Malformed path |
| 404 | No passport at this address, a draft, or a link type the passport does not have |
| 410 | Withdrawn or archived |
| 429 | Too many requests from one address |