Public API overview
DPP Agent exposes a small, REST-style HTTP API for creating, reading, and managing Digital Product Passports across every industry the EU's ESPR roadmap touches — textile, electronics, batteries, cosmetics, tyres, construction, furniture, and more.
This reference is generic across industries. Endpoint signatures are
identical regardless of category; only the keys inside dpp_data
differ. See the per-category schemas (espr-base, tex.*, bat.*,
ict.*, cos.*, con.*, tyr.*) for the structured fields each
sector uses.
Base URLs
| Layer | URL | Notes |
|---|---|---|
| Resolver (public DPP read) | https://{slug}.dpp.dppagent.com |
Consumer-scan endpoint. Custom-tier brands replace with their own domain via CNAME. |
| Management API | https://dppagent.com/api/v1 |
Authoring + admin endpoints used by integrations and tenant dashboards. |
| Static docs | https://docs.dppagent.com |
This reference. |
The resolver is read-only and CDN-cached. The management API is authored writes and authenticated reads.
Authentication
Three styles, picked per endpoint.
1. None (public scan). Every consumer-scan endpoint under the
resolver host is unauthenticated. Response shape negotiated via
Accept header per EN 18216 §5.
2. Bearer token. Every authoring endpoint under
/api/v1/ requires Authorization: Bearer <token>. Tenants
generate their tokens under Settings → API in the dashboard.
GET /api/v1/dpps/abc-123
Authorization: Bearer dpp_live_a8b1c2d3e4...
Tokens are tenant-scoped. They never let a caller read another tenant's data even if the request body claims otherwise. Rotate tokens at any time — old tokens are invalidated immediately.
3. Supabase session (browser-only). The dashboard UI signs in operators through Supabase. This is an implementation detail — external integrators always use Bearer tokens.
Conventions
- Format: requests + responses are JSON unless stated otherwise.
Content-Type: application/json; charset=utf-8. - Identifiers: every DPP carries an opaque UUID (
id) and a canonical passport URL (passport_id). Pass either when reading. - Datetimes: ISO 8601 with timezone offset
(
2026-06-26T13:42:05.000Z). - Country / currency: ISO 3166-1 alpha-2 (
SE,DK,FR), ISO 4217 (EUR,SEK). - Pagination: list endpoints accept
?limit=(max 100, default- and
?cursor=(opaque). Responses includenext_cursorwhen more rows exist.
- and
Versioning
The API is on v1. Backwards-incompatible changes ship behind a
new major version (v2, v3 …) — never inside v1. Additive
changes (new fields, new endpoints, new optional parameters) ship
without a version bump.
Error format
Errors return a non-2xx HTTP status and a JSON body with a stable shape:
{
"error": "validation_failed",
"message": "gtin must be 13 or 14 digits",
"details": {
"field": "gtin",
"value": "0073-bad-input"
}
}
Error codes you'll meet most often:
| Code | HTTP | Meaning |
|---|---|---|
authentication_required |
401 | Bearer token missing |
authentication_invalid |
401 | Token rejected — rotate it |
forbidden |
403 | Token is valid but scoped to a different tenant |
not_found |
404 | DPP, tenant, or endpoint doesn't exist |
validation_failed |
400 | Required field missing or malformed |
conflict |
409 | GTIN / batch / serial already in use |
quota_exceeded |
429 | Plan quota or rate-limit hit |
internal_error |
500 | Bug on our side — capture the response and ping support |
Rate limits
Default limits per tenant:
- Resolver reads: unlimited, CDN-cached. Burst-tolerant.
- Authoring writes: 60 requests per minute, 5 000 per day.
- AI Suggest / extraction: 30 requests per minute, 1 000 per day.
- Bulk imports: 5 concurrent jobs.
The X-RateLimit-Remaining, X-RateLimit-Limit, and
X-RateLimit-Reset headers are present on every authenticated
response. Hitting the cap returns 429 quota_exceeded with a
Retry-After header in seconds.
Custom-tier plans bump these limits. Talk to support if you need more.
CORS
The resolver allows requests from any origin (Access-Control-Allow-Origin: *)
for cross-site validators, scanner apps, and external integrations.
The management API allows requests only from the tenant's own
domain and dashboards.
Caching
Resolver responses set Cache-Control based on DPP status:
| Status | Max-age |
|---|---|
active, replaced |
5 minutes (CDN), 30 seconds (browser) |
draft |
10 seconds |
withdrawn, archived |
10 seconds |
| Not found | 10 seconds |
QR codes and label SVGs cache for 1 day — they only change when the underlying template or DPP data changes.
Sandbox
Each tenant has a sandbox mode toggle on Settings → API. Sandbox
tokens write to an isolated, ephemeral dataset and never appear on
public resolver URLs. Same surface, same error codes — just no
real-world consequences.
Status & uptime
status.dppagent.com shows live status of the resolver, management
API, and dashboard. Incidents post there before they post in chat.
Next
- Resolver — public DPP scan endpoint
- DPPs — create, read, update, delete passports
- Tenants — manage your brand profile + custom domains
- Certifications — register certs that auto-apply to matching DPPs
- Suppliers — supplier registry with journey-block overlay
- Files — attach DoP, SDS, technical files at tenant or per-DPP scope
- QR & Labels — generate codes and label SVGs
- Validate — system conformance + ESPR Base coverage checker
- Errors — full error code catalogue