DPPs — create, read, update, delete
The DPP is the central object — one row per product (model granularity) or product instance (item granularity, with batch + serial). Every endpoint here is tenant-scoped via the Bearer token.
Object shape
{
"id": "dpp_3f2a9b1c-e0d8-4f8e-b308-d2541886e331",
"tenant_id": "tnt_8d3a4f91-427f-4d5d-b527-c0b28363676c",
"passport_id": "https://example.dpp.dppagent.com/01/07314781685466/21/AX-001",
"gtin": "07314781685466",
"batch": null,
"serial": "AX-001",
"cpv": null,
"category": "electronics",
"granularity": "item",
"identifier_scheme": "01",
"template_id": "electronics-premium",
"dpp_status": "active",
"dpp_data": { /* ESPR Base + category-specific keys */ },
"last_updated": "2026-06-26T13:42:05.000Z",
"created_at": "2026-05-10T09:18:21.000Z"
}
dpp_data carries the structured payload. Keys are flat strings
(espr.pid.product_name, bat.chem.cell_chemistry,
ict.energy.eu_efficiency_class) so any consumer can read with a
single hash lookup. See per-category schemas for what keys exist.
Create one DPP
POST /api/v1/dpps
Authorization: Bearer dpp_live_…
Content-Type: application/json
{
"tenant_id": "tnt_8d3a4f91-…",
"gtin": "07314781685466",
"category": "electronics",
"granularity": "model",
"template_id": "electronics-premium",
"dpp_data": {
"espr.pid.product_name": "Beosound Explore",
"espr.pid.product_brand": "Bang & Olufsen",
"espr.mfr.name": "B&O A/S",
"espr.eo.country": "DK",
"ict.energy.eu_efficiency_class": "A"
}
}
Response — 201 Created:
{
"id": "dpp_3f2a9b1c-…",
"passport_id": "https://bang-olufsen.dpp.dppagent.com/01/07314781685466",
"dpp_status": "draft"
}
The DPP starts as a draft. Promote it by patching
dpp_status: "active" once mandatory fields are filled.
Async creation
Item-granularity DPPs with quantity > 1000 enqueue an
async serialization job and return 202 Accepted:
{
"job_id": "sj_8c3a4f91-…",
"status_url": "/api/v1/dpps/jobs/sj_8c3a4f91-…"
}
Poll status_url until the job reports completed.
Bulk create
POST /api/v1/dpps-batch
{
"tenant_id": "tnt_…",
"stop_on_error": false,
"items": [
{ "gtin": "0731…0001", "category": "battery", "granularity": "model", "dpp_data": {} },
{ "gtin": "0731…0002", "category": "battery", "granularity": "model", "dpp_data": {} }
]
}
Up to 1 000 items per call. Response includes per-item success
status — partial successes are normal when stop_on_error: false.
Read one DPP
GET /api/v1/dpps/{id}
Returns the full object including dpp_data. Add ?include=versions
to inline the version history.
Update a DPP
PATCH /api/v1/dpps/{id}
Content-Type: application/json
{
"tenant_id": "tnt_…",
"dpp_data": {
"espr.pid.product_name": "Beosound Explore II",
"ict.energy.eu_efficiency_class": "A+"
}
}
PATCH is a shallow merge at the top level — your dpp_data
replaces the stored map wholesale. To merge subset of keys, read,
mutate, write.
Status transitions are also a PATCH:
{ "tenant_id": "tnt_…", "dpp_status": "active" }
Valid status values: draft, active, replaced, withdrawn,
archived. Going from active straight to archived triggers a
HTTP 410 Gone on the resolver — meaning the consumer scan still
resolves but indicates the product is gone.
Delete a DPP
DELETE /api/v1/dpps/{id}
Hard-deletes drafts. active, withdrawn, and archived DPPs
cannot be hard-deleted — change dpp_status to archived instead
so the audit trail and version history survive.
Find DPPs by GTIN
GET /api/v1/dppsByProductId/{gtin}
Returns the most recent active DPP for a product identifier. Useful for stamp-on-product flows where the integration only knows the GTIN, not the DPP id.
Per-DPP analytics
GET /api/v1/dpps/{id}/analytics?days=90
Returns { total, daily: [{ day, count }], by_country: [{ country, count }], by_device: { mobile, desktop, tablet, unknown }, recent: [{ scanned_at, country, device_class, referer_host, accept_lang, ip_prefix, user_agent }] }.
Default window 90 days, override with ?days=.
Version history
GET /api/v1/dpps/{id}/versions
Every PATCH writes a snapshot. Response includes a field-level diff against the previous version — useful for audit trails and regulator queries.
AI Suggest
POST /api/v1/dpps/ai-suggest
{
"dppId": "dpp_…",
"fields": ["espr.pid.product_name", "espr.mat.components"]
}
Returns suggested values pulled from integration raw data (Centra, Delogue, Shopify, etc.) or AI-extracted from the brand site, with a source citation per field. Operators review and accept; nothing auto-writes.
Sync from datasource
POST /api/v1/dpps/{id}/sync-from-datasource
Re-pulls this DPP from its origin integration. Useful after a brand edits the source-of-truth in their PIM and wants the DPP to refresh without waiting for the next scheduled sync.