DPP Agent docs

Error code catalogue

Every error returns a JSON body shaped like:

{
  "error": "<machine_code>",
  "message": "<human-readable summary>",
  "details": { "field": "gtin", "value": "0073-bad-input" }
}

details is optional and varies per error. Code (error) is stable — machine consumers should switch on it. Message is human-friendly and may change.

Authentication / authorisation

authentication_required — 401

No Authorization: Bearer … header. Add a token from Settings → API.

authentication_invalid — 401

Token rejected. The token may have been rotated, expired, or mistyped. Generate a fresh one from Settings → API.

forbidden — 403

Token is valid but scoped to a different tenant than the one named in the path or body. Each tenant has its own tokens — a Brand A token can never read Brand B data.

Validation

validation_failed — 400

Required field missing or malformed. details.field says which key and details.value shows what you sent.

Common triggers:

  • GTIN not 13 or 14 digits
  • granularity not one of model / batch / item
  • dpp_status invalid transition (e.g. draft → archived straight)
  • Country / currency / language not ISO-coded

conflict — 409

The combination of GTIN + batch + serial + CPV already exists. Either update the existing DPP via PATCH or pick different identifiers.

not_found — 404

DPP / tenant / file does not exist. May also mean the resource exists but is scoped to another tenant — we return 404 rather than 403 so attackers can't enumerate IDs.

Quotas

quota_exceeded — 429

Plan quota or rate limit hit. The response includes a Retry-After header in seconds. Headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset are present so the client can self-pace.

Custom-tier plans bump limits — contact support to upgrade.

plan_locked — 402

Feature not available on the current plan (e.g. custom domains on Light tier, AI Suggest on Free tier). Upgrade required.

Server-side

internal_error — 500

Bug on our side. The response body includes a request_id — pass that to support so we can pull the trace.

upstream_unavailable — 502

A downstream dependency (PIM, Stripe, AI provider) was unreachable. Retry with exponential backoff. The error usually self-clears.

maintenance — 503

Scheduled maintenance window. The Retry-After header shows when to retry. Posted in advance on status.dppagent.com.

Resolver-specific

withdrawn — 200 with X-DPP-Status: withdrawn

Not technically an error. The DPP exists but is marked withdrawn — consumer still sees the passport but with a "this product is no longer sold" notice. Header X-DPP-Status flips so integrators can branch.

archived — 410 Gone

The DPP was archived. Consumer page renders a "this product has been retired" notice. The archived flag is permanent — once archived, always archived.

Webhook delivery

Webhooks deliver with retries. After 5 failed attempts the event moves to dead-letter. Failures show in the dashboard under Settings → API → Webhooks.