Clone the repository

May 10, 2026 · View on GitHub

dppvalidator logo

dppvalidator

The open-source compliance engine for EU Digital Product Passports

PyPI version Python versions Downloads License CI Documentation

Platform

InstallationQuick StartFeaturesDocumentationContributing


dppvalidator is a Python library for validating Digital Product Passports (DPP) according to EU ESPR regulations, the UNTP DPP specification, and the CIRPASS DPP reference structure.

Starting 2027, every textile and apparel product sold in the EU must have a Digital Product Passport. This library ensures your DPP data is compliant before it hits production — saving fashion brands from costly compliance failures and enabling seamless integration with the circular economy.

Why dppvalidator?

ChallengeSolution
Complex JSON Schema validationSeven-layer validation catches errors at schema, model, semantic, JSON-LD, vocabulary, plugin, and signature levels
Evolving UNTP specificationsBoth UNTP DPP 0.6.x and 0.7.0 — auto-detected; dppvalidator migrate upgrades 0.6 → 0.7
Integration with existing systemsCLI + Python API for pipelines, CI/CD, and application integration
Custom business rulesPlugin system for domain-specific validators and exporters
Interoperability requirementsJSON-LD export for W3C Verifiable Credentials compliance

Installation

# Using uv (recommended)
uv add dppvalidator

# With CLI extras (rich formatting)
uv add "dppvalidator[cli]"

# Or using pip
pip install dppvalidator
pip install "dppvalidator[cli]"  # with CLI extras

Optional Features

RDF/SHACL Validation

For SHACL validation against official CIRPASS-2 shapes:

# Using uv (recommended)
uv add "dppvalidator[rdf]"

# Or using pip
pip install "dppvalidator[rdf]"
from dppvalidator.validators import ValidationEngine

# Enable SHACL validation (requires [rdf] extra)
engine = ValidationEngine(enable_shacl=True)
result = engine.validate(dpp_data)

JSON-LD Semantic Validation

JSON-LD validation is included by default (via pyld):

engine = ValidationEngine(validate_jsonld=True)
result = engine.validate(dpp_data)

Signature Verification

Signature verification is included by default (via cryptography):

engine = ValidationEngine(verify_signatures=True)
result = engine.validate(dpp_data)

Note: pyld and cryptography are core dependencies installed automatically. Only [rdf] (for SHACL via rdflib/pyshacl) and [cli] (for rich formatting) are true optional extras.

Requirements: Python 3.10+

Quick Start

Validate a DPP

from dppvalidator.validators import ValidationEngine

engine = ValidationEngine()

result = engine.validate(
    {
        "id": "https://example.com/dpp/battery-001",
        "type": ["DigitalProductPassport", "VerifiableCredential"],
        "issuer": {
            "id": "https://example.com/manufacturer",
            "name": "Acme Battery Co.",
        },
        "credentialSubject": {
            "id": "https://example.com/product/battery-001",
            "product": {
                "name": "EV Battery Pack",
                "description": "High-capacity lithium-ion battery",
            },
        },
    }
)

if result.valid:
    print(f"✓ Valid in {result.validation_time_ms:.2f}ms")
else:
    for error in result.errors:
        print(f"✗ [{error.code}] {error.path}: {error.message}")

Command Line

# Validate a DPP file
dppvalidator validate passport.json

# Strict mode - warnings become errors
dppvalidator validate passport.json --strict

# Export to JSON-LD (W3C Verifiable Credential format)
dppvalidator export passport.json --format jsonld --output passport.jsonld

# Display schema information
dppvalidator schema --version 0.6.1

Export to JSON-LD

from dppvalidator.models import DigitalProductPassport, CredentialIssuer
from dppvalidator.exporters import JSONLDExporter

passport = DigitalProductPassport(
    id="https://example.com/dpp/product-001",
    issuer=CredentialIssuer(
        id="https://example.com/issuer", name="Sustainable Textiles Ltd."
    ),
)

exporter = JSONLDExporter()
jsonld_output = exporter.export(passport)
# Ready for W3C Verifiable Credentials ecosystem

Supported specs

dppvalidator validates two parallel families in the same release: UNTP DPP (UN/CEFACT Verifiable Credential format) and the CIRPASS DPP reference structure (CIRPASS-2 hierarchical message). Family + version are auto-detected from the payload's @context / shape; pin explicitly with --target (family) and --schema-version (version), or target= / schema_version= in Python.

UNTP DPP

VersionStatusDefault?Wire shape
0.6.0Supported (legacy)nocredentialSubject is ProductPassport wrapping Product.
0.6.1Supported (legacy)noSame shape as 0.6.0.
0.7.0DefaultyescredentialSubject IS the Product directly. New required fields: name (envelope), idScheme, idGranularity, productCategory, producedAtFacility, countryOfProduction; current DEFAULT_SCHEMA_VERSION.

CIRPASS DPP reference structure

VersionStatusDefault?Wire shape
1.3.0Fully supportedyesHierarchical message: root carries dppIdentifier, product, issuedAt, effectivePeriod, relatedActors, composition, substancesOfConcern, lca, connectorRelations.

EUDPP modules bundled: P_DPP / ACTOR / SOC / CON v1.9.1, LCA v1.9.4-Maki. Per-module SHACL pass with attributed source (Phase 4).

Migration shims

Two shims project between families and across UNTP versions:

# UNTP 0.6 → 0.7 (intra-family upgrade)
dppvalidator migrate passport-v06.json -o passport-v07.json

# UNTP 0.7 → CIRPASS reference structure 1.3 (cross-family forward)
dppvalidator migrate passport-v07.json --to cirpass-1.3 -o cirpass.json --accept-warnings

# CIRPASS 1.3 → UNTP 0.7 (cross-family reverse)
dppvalidator migrate cirpass.json --to untp-0.7 -o untp.json --accept-warnings

Pilot profiles + plugins

PilotActivationSource
Textile DPP v1 (legacy)--profile textile-v1built-in
Textile DPP v2 (MVP 2025-12-04)--profile textile-v2built-in
Tyres (GDSO Birth/Collection/Retread/Recycling)pip install dppvalidator-tyresplugins/tyres/ — Pre-1.0 / Experimental, GPL-3.0

Reading guide

You want…See
Big-picture orientationdocs/concepts/cirpass-2-alignment.md
Migrate a UNTP fixture to CIRPASSdocs/guides/migrate-untp-to-cirpass.md
UNTP version handlingdocs/concepts/untp-versions.md
0.6 → 0.7 upgradedocs/guides/migration-0-6-to-0-7.md
Field-by-field UNTP↔CIRPASS mapdocs/concepts/untp-cirpass-mapping.md
CLI exit codesdocs/reference/cli/exit-codes.md
CIRPASS Pydantic APIdocs/reference/cirpass/index.md

Features

Seven-Layer Validation Architecture

flowchart TD
    subgraph Input
        A[/"📄 Input Data (JSON)"/]
    end

    subgraph Layer0["Layer 0: Detection"]
        A0["Auto-detect family + version<br/>from $schema, @context, type"]
    end

    subgraph Layer1["Layer 1: Schema"]
        B["JSON Schema Draft 2020-12<br/>Required fields, types, formats"]
    end

    subgraph Layer2["Layer 2: Model"]
        C["Pydantic v2 Models<br/>Type coercion, URL validation"]
    end

    subgraph Layer3["Layer 3: JSON-LD"]
        C2["PyLD Expansion<br/>Context resolution, term validation"]
    end

    subgraph Layer4["Layer 4: Semantic"]
        D["Business rules<br/>Date logic, GTIN checksums, sums"]
    end

    subgraph Layer5["Layer 5: Vocabulary"]
        D2["External code lists<br/>ISO 3166, UNECE Rec 20/46, HS"]
    end

    subgraph Layer6["Layer 6: Plugin"]
        D3["Per-pack rules<br/>e.g. textile TXT, CIRPASS CQ, tyre TYR"]
    end

    subgraph Layer7["Layer 7: Signature (reserved)"]
        E["VC signature verification<br/>DID resolution, Ed25519/ECDSA"]
    end

    subgraph Output
        F[/"✅ ValidationResult<br/>.valid | .errors | .signature_valid"/]
    end

    A --> A0
    A0 --> B
    B -->|"SCH001-SCH099"| C
    C -->|"MDL001-MDL099"| C2
    C2 -->|"JLD001-JLD099"| D
    D -->|"SEM001-SEM099"| D2
    D2 -->|"VOC001-VOC099"| D3
    D3 -->|"plugin-specific"| E
    E -->|"reserved"| F

Layer 7 codes (SIG001SIG099) are reserved for the future structured-code migration; the verifier currently surfaces untyped error strings via VerificationResult.errors. See ADR 0006 for the canonical layer + prefix table, including non-layer codes (PRS, DET, VER, UPG, MAP, PRT).

Selective Layer Validation

from dppvalidator.validators import ValidationEngine

# Run all layers (default)
engine = ValidationEngine()

# Schema validation only (fastest)
engine = ValidationEngine(layers=["schema"])

# Skip schema, run model + semantic
engine = ValidationEngine(layers=["model", "semantic"])

# Enable JSON-LD validation
engine = ValidationEngine(validate_jsonld=True)

# Enable signature verification
engine = ValidationEngine(verify_signatures=True)
result = engine.validate(dpp_data)
if result.signature_valid:
    print(f"Signed by: {result.issuer_did}")

Performance

LayerMean TimeThroughput
Model (minimal)0.012ms84,387 ops/sec
Model (full)0.016ms63,945 ops/sec
Semantic0.005ms200,889 ops/sec
Full (Model+Sem)0.022ms45,735 ops/sec
Engine Creation0.001ms1,524,868 ops/sec

Benchmarked on Apple Silicon (M-series). JSON-LD and signature verification depend on network latency (cached after first request).

Plugin System

Extend dppvalidator with custom validators following the SemanticRule protocol:

from dppvalidator.plugins import PluginRegistry


# Create a custom validator implementing SemanticRule protocol
class TextileFiberRule:
    """Custom rule to validate textile fiber composition."""

    rule_id = "TEX001"
    description = "Fiber composition must sum to 100%"
    severity = "error"
    suggestion = "Ensure all fiber percentages add up to 100"
    docs_url = "https://example.com/textile-rules"

    def check(self, passport):
        """Return list of (json_path, error_message) tuples."""
        violations = []
        # Add your validation logic here
        return violations


# Register with the plugin registry
registry = PluginRegistry(auto_discover=False)
registry.register_validator("textile", TextileFiberRule)

# ValidationEngine auto-discovers plugins via entry points by default
engine = ValidationEngine(load_plugins=True)

EU DPP & CIRPASS-2 Support

dppvalidator includes full support for the EU DPP Core Ontology from CIRPASS-2:

from dppvalidator.validators import SchemaValidator
from dppvalidator.exporters import EUDPPJsonLDExporter

# Dual-mode validation: UNTP (default) or EU DPP
validator = SchemaValidator(schema_type="cirpass")
result = validator.validate(dpp_data)

# Export to EU DPP-aligned JSON-LD
exporter = EUDPPJsonLDExporter(map_terms=True)
jsonld = exporter.export(passport)
FeatureDescription
Dual-mode validationSwitch between UNTP and CIRPASS schemas
EU DPP vocabulary24 actor/role classes, 16 PEF categories
JSON-LD exportEU DPP-aligned output with term mapping
SHACL validationOptional RDF-based validation (requires pip install dppvalidator[rdf])

🏆 Aligned with dpp.vocabulary-hub.eu/specifications as of 2025-02-01. To our knowledge, dppvalidator is the most comprehensive open-source Python package for EU DPP vocabulary compliance.

Documentation

📚 Full documentation: artiso-ai.github.io/dppvalidator

GuideDescription
InstallationSetup and CLI extras
Quick StartGet started in 5 minutes
CLI ReferenceCommand-line interface
Validation LayersUnderstanding the seven-layer architecture
CIRPASS-2 IntegrationEU DPP ontology alignment
API ReferenceComplete Python API

Built for Fashion & Textiles

The EU's Ecodesign for Sustainable Products Regulation (ESPR) mandates Digital Product Passports for textiles starting 2027. dppvalidator helps fashion brands prepare now:

DPP RequirementHow dppvalidator Helps
Material composition & weightsValidates fiber percentages sum to 100%
Manufacturing processesValidates supply chain node structure
Environmental indicatorsSupports LCA data validation
Chemical compliance (REACH)Semantic validation for substance references
Traceability informationValidates production stage URIs
Durability & recyclabilityCustom validators via plugin system

Use Cases

dppvalidator serves diverse stakeholders across the product lifecycle:

Use CaseTarget UserValue Proposition
Pre-production validationBrand product teamsCatch errors before QR code generation
Supplier onboardingProcurement teamsValidate supplier DPP submissions
CI/CD compliance gatesDevOps teamsAutomated compliance checks in pipelines
Data migrationIT teamsValidate legacy data exports to DPP format
Consumer appsApp developersDPP scanning, parsing, and display
Recycling facilitiesWaste managementMaterial identification for sorting
Resale platformsRecommerceProduct authentication and history
Customs & complianceBorder controlImport compliance verification

Example: CI/CD Integration

# .github/workflows/validate-dpp.yml
- name: Validate DPP files
  run: dppvalidator validate data/passports/*.json --strict

Example: Supplier Validation API

from dppvalidator.validators import ValidationEngine

engine = ValidationEngine(strict_mode=True)


def validate_supplier_submission(dpp_json: dict) -> bool:
    result = engine.validate(dpp_json)
    if not result.valid:
        raise ValueError(f"Invalid DPP: {result.errors}")
    return True

⚠️ Note on UNTP Specification: The UNTP Digital Product Passport specification is under active development and not yet ready for production implementation. We track the latest maintained releases and will update dppvalidator as the specification stabilizes. See the UNTP releases page for current status.

Known Limitations

Signature Verification

FeatureStatusRecommendation
Data Integrity Proofs✅ SupportedUse for production
JWS Proofs✅ SupportedUse for production
JWT Credentials✅ SupportedFull verification (ES256, ES384, EdDSA)

JWT Credentials: JWT-encoded Verifiable Credentials are fully verified via DID resolution and cryptographic signature verification. Supported algorithms include ES256, ES384, and EdDSA (Ed25519). For maximum interoperability, Data Integrity Proofs are recommended.

Canonicalization

The signature verification uses simplified JSON canonicalization (sorted keys) rather than full URDNA2015 RDF canonicalization. This may cause verification failures for credentials signed with strict W3C Data Integrity canonicalization.

For production deployments requiring full W3C VC compliance:

# Future: Use pyld for URDNA2015 canonicalization
from pyld import jsonld

normalized = jsonld.normalize(credential, {"algorithm": "URDNA2015"})

Contributing

We welcome contributions! Here's how to get started:

# Clone the repository
git clone https://github.com/artiso-ai/dppvalidator.git
cd dppvalidator

# Install dependencies with uv
uv sync --all-extras

# Run tests
uv run pytest

# Run linting
uv run ruff check .

See our Contributing Guide for more details.

About ARTISO

dppvalidator is developed and maintained by ARTISO, a Barcelona-based fashion technology company.

ARTISO

We believe the fashion industry's transition to sustainability requires open, accessible tools. By open-sourcing dppvalidator, we're enabling brands of all sizes - from emerging designers to global retailers - to meet EU compliance requirements without proprietary solutions.

Our commitment:

  • Open Source First - Core validation engine will always be free and MIT-licensed
  • Fashion Expertise - Built by a team with deep industry experience at major brands
  • Circular Economy - Enabling the data infrastructure for textile recycling and resale
  • Community Driven - We welcome contributions from brands, sustainability experts, and developers

"The circular economy can only work if recyclers can read the tags. dppvalidator ensures interoperability across the entire fashion supply chain."

License

MIT License — see LICENSE for details.


artiso.ai · Documentation · Issues

Built with ❤️ in Barcelona for a more sustainable fashion industry