Skip to content

Use Cases

Real-world examples of how to use dppvalidator across different scenarios and industries.


Fashion & Textiles Compliance

Pre-Production Validation

Validate DPP data before generating QR codes for garment labels.

from dppvalidator import ValidationEngine
from dppvalidator.vocabularies import validate_gtin, is_valid_material_code

engine = ValidationEngine(strict_mode=True)


def validate_garment_dpp(dpp_data: dict) -> dict:
    """Validate garment DPP before QR code generation."""
    result = engine.validate(dpp_data)

    if not result.valid:
        return {
            "status": "rejected",
            "errors": [
                {"code": e.code, "path": e.path, "message": e.message}
                for e in result.errors
            ],
        }

    return {
        "status": "approved",
        "passport_id": dpp_data.get("id"),
        "ready_for_qr": True,
    }


# Example garment DPP
garment_dpp = {
    "type": ["DigitalProductPassport", "VerifiableCredential"],
    "@context": [
        "https://www.w3.org/ns/credentials/v2",
        "https://test.uncefact.org/vocabulary/untp/dpp/0.6.1/",
    ],
    "id": "https://brand.com/dpp/organic-dress-2024-001",
    "issuer": {
        "id": "did:web:brand.com",
        "name": "Sustainable Fashion Brand",
    },
    "validFrom": "2024-06-01T00:00:00Z",
    "validUntil": "2034-06-01T00:00:00Z",
    "credentialSubject": {
        "type": ["Product"],
        "id": "https://brand.com/products/organic-dress-001",
        "name": "Organic Cotton Summer Dress",
        "granularityLevel": "model",
        "materialsProvenance": [
            {
                "type": ["Material"],
                "name": "GOTS Organic Cotton",
                "massFraction": 0.95,
                "recycled": False,
                "hazardous": False,
            },
            {
                "type": ["Material"],
                "name": "Elastane",
                "massFraction": 0.05,
                "recycled": False,
                "hazardous": False,
            },
        ],
        "circularityScorecard": {
            "type": ["CircularityScorecard"],
            "recycledContent": 0.0,
            "recyclableContent": 0.92,
        },
    },
}

result = validate_garment_dpp(garment_dpp)
print(result)

Material Composition Validation

Ensure fiber compositions are accurate and sum correctly.

from dppvalidator import ValidationEngine

engine = ValidationEngine()


def check_fiber_composition(dpp_data: dict) -> dict:
    """Check fiber composition adds up to 100%."""
    result = engine.validate(dpp_data)

    materials = dpp_data.get("credentialSubject", {}).get("materialsProvenance", [])

    total_fraction = sum(m.get("massFraction", 0) for m in materials)

    return {
        "valid": result.valid,
        "total_composition": f"{total_fraction * 100:.1f}%",
        "materials": [
            {
                "name": m.get("name"),
                "percentage": f"{m.get('massFraction', 0) * 100:.1f}%",
            }
            for m in materials
        ],
        "composition_complete": abs(total_fraction - 1.0) < 0.01,
    }

Supplier Onboarding

Supplier DPP Validation API

Validate DPP submissions from suppliers before accepting them.

from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from dppvalidator import ValidationEngine

app = FastAPI(title="Supplier DPP Validation API")
engine = ValidationEngine(strict_mode=True)


class SubmissionResponse(BaseModel):
    accepted: bool
    submission_id: str | None = None
    errors: list[dict] | None = None


@app.post("/api/v1/supplier/submit-dpp", response_model=SubmissionResponse)
async def submit_dpp(dpp: dict, supplier_id: str):
    """Validate and accept supplier DPP submission."""

    # Validate the DPP
    result = engine.validate(dpp)

    if not result.valid:
        return SubmissionResponse(
            accepted=False,
            errors=[
                {
                    "code": e.code,
                    "field": e.path,
                    "message": e.message,
                    "suggestion": e.suggestion,
                }
                for e in result.errors
            ],
        )

    # DPP is valid - store it
    submission_id = f"SUB-{supplier_id}-{dpp.get('id', '').split('/')[-1]}"

    return SubmissionResponse(
        accepted=True,
        submission_id=submission_id,
    )


@app.post("/api/v1/supplier/batch-validate")
async def batch_validate(dpps: list[dict]):
    """Validate multiple DPPs in one request."""
    results = await engine.validate_batch(dpps, concurrency=10)

    return {
        "total": len(dpps),
        "valid": sum(1 for r in results if r.valid),
        "invalid": sum(1 for r in results if not r.valid),
        "results": [
            {
                "index": i,
                "valid": r.valid,
                "error_count": r.error_count,
            }
            for i, r in enumerate(results)
        ],
    }

Supplier Quality Dashboard

Aggregate validation results for supplier quality scoring.

from collections import Counter
from dataclasses import dataclass
from dppvalidator import ValidationEngine


@dataclass
class SupplierQualityReport:
    supplier_id: str
    total_submissions: int
    valid_count: int
    invalid_count: int
    pass_rate: float
    common_errors: list[tuple[str, int]]


def analyze_supplier_submissions(
    supplier_id: str,
    submissions: list[dict],
) -> SupplierQualityReport:
    """Analyze a supplier's DPP submission quality."""
    engine = ValidationEngine()

    error_codes = []
    valid_count = 0

    for dpp in submissions:
        result = engine.validate(dpp)
        if result.valid:
            valid_count += 1
        else:
            error_codes.extend(e.code for e in result.errors)

    return SupplierQualityReport(
        supplier_id=supplier_id,
        total_submissions=len(submissions),
        valid_count=valid_count,
        invalid_count=len(submissions) - valid_count,
        pass_rate=valid_count / len(submissions) if submissions else 0,
        common_errors=Counter(error_codes).most_common(5),
    )

CI/CD Pipeline Integration

GitHub Actions Workflow

Add DPP validation as a CI/CD gate.

# .github/workflows/validate-dpps.yml
name: Validate Digital Product Passports

on:
  push:
    paths:
      - 'data/passports/**/*.json'
  pull_request:
    paths:
      - 'data/passports/**/*.json'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dppvalidator
        run: pip install dppvalidator

      - name: Validate all DPP files
        run: |
          find data/passports -name "*.json" -exec \
            dppvalidator validate {} --strict --format json \;

      - name: Generate validation report
        if: always()
        run: |
          echo "## DPP Validation Report" >> $GITHUB_STEP_SUMMARY
          for f in data/passports/*.json; do
            result=$(dppvalidator validate "$f" --format json 2>&1 || true)
            valid=$(echo "$result" | jq -r '.valid')
            if [ "$valid" = "true" ]; then
              echo "✅ $(basename $f)" >> $GITHUB_STEP_SUMMARY
            else
              echo "❌ $(basename $f)" >> $GITHUB_STEP_SUMMARY
            fi
          done

Pre-Commit Hook

Validate DPP files before committing.

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: validate-dpps
        name: Validate DPP files
        entry: dppvalidator validate
        language: python
        types: [json]
        files: ^data/passports/.*\.json$
        additional_dependencies: [dppvalidator]

Python CI Script

Programmatic validation for complex pipelines.

#!/usr/bin/env python3
"""CI script for DPP validation with detailed reporting."""

import json
import sys
from pathlib import Path
from dppvalidator import ValidationEngine


def validate_directory(directory: Path) -> int:
    """Validate all DPP files in a directory."""
    engine = ValidationEngine(strict_mode=True)

    files = list(directory.glob("**/*.json"))
    if not files:
        print(f"No JSON files found in {directory}")
        return 0

    failed = 0
    for path in files:
        try:
            data = json.loads(path.read_text())
            result = engine.validate(data)

            if result.valid:
                print(f"✅ {path.name}")
            else:
                print(f"❌ {path.name}")
                for error in result.errors:
                    print(f"   [{error.code}] {error.path}: {error.message}")
                failed += 1

        except json.JSONDecodeError as e:
            print(f"❌ {path.name}: Invalid JSON - {e}")
            failed += 1

    print(f"\n{'='*50}")
    print(f"Total: {len(files)} | Passed: {len(files) - failed} | Failed: {failed}")

    return failed


if __name__ == "__main__":
    directory = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("data/passports")
    sys.exit(validate_directory(directory))

Data Migration

Legacy System Migration

Convert and validate legacy product data to DPP format.

from datetime import datetime, timezone
from dppvalidator import ValidationEngine
from dppvalidator.models import DigitalProductPassport, CredentialIssuer


def migrate_legacy_product(legacy: dict, issuer_id: str) -> dict:
    """Convert legacy product data to DPP format."""
    return {
        "type": ["DigitalProductPassport", "VerifiableCredential"],
        "@context": [
            "https://www.w3.org/ns/credentials/v2",
            "https://test.uncefact.org/vocabulary/untp/dpp/0.6.1/",
        ],
        "id": f"https://company.com/dpp/{legacy['sku']}",
        "issuer": {
            "id": issuer_id,
            "name": legacy.get("brand", "Unknown"),
        },
        "validFrom": datetime.now(timezone.utc).isoformat(),
        "validUntil": "2035-01-01T00:00:00Z",
        "credentialSubject": {
            "type": ["Product"],
            "id": f"https://company.com/products/{legacy['sku']}",
            "name": legacy["name"],
            "description": legacy.get("description", ""),
            "granularityLevel": "model",
        },
    }


def migrate_and_validate(
    legacy_products: list[dict],
    issuer_id: str,
) -> dict:
    """Migrate legacy products and validate the results."""
    engine = ValidationEngine()

    results = {
        "migrated": [],
        "failed": [],
    }

    for legacy in legacy_products:
        dpp = migrate_legacy_product(legacy, issuer_id)
        result = engine.validate(dpp)

        if result.valid:
            results["migrated"].append(
                {
                    "sku": legacy["sku"],
                    "dpp_id": dpp["id"],
                    "status": "success",
                }
            )
        else:
            results["failed"].append(
                {
                    "sku": legacy["sku"],
                    "errors": [e.message for e in result.errors],
                }
            )

    return results


# Example usage
legacy_data = [
    {"sku": "SHIRT-001", "name": "Cotton T-Shirt", "brand": "EcoBrand"},
    {"sku": "DRESS-002", "name": "Summer Dress", "brand": "EcoBrand"},
]

migration_results = migrate_and_validate(
    legacy_data,
    issuer_id="did:web:ecobrand.com",
)
print(f"Migrated: {len(migration_results['migrated'])}")
print(f"Failed: {len(migration_results['failed'])}")

Supply Chain Traceability

Deep Validation of Supply Chain

Validate entire supply chains by following linked documents.

import asyncio
from dppvalidator import ValidationEngine


async def validate_supply_chain(root_dpp: dict) -> dict:
    """Validate a product's entire supply chain."""
    engine = ValidationEngine(
        validate_jsonld=True,
        verify_signatures=True,
    )

    result = await engine.validate_deep(
        root_dpp,
        max_depth=5,
        follow_links=[
            "credentialSubject.traceabilityEvents",
            "credentialSubject.conformityClaim",
            "credentialSubject.materialsProvenance",
        ],
        timeout=60.0,
    )

    return {
        "root_valid": result.root_result.valid,
        "total_documents": result.total_documents,
        "all_valid": result.valid,
        "max_depth_reached": result.max_depth_reached,
        "cycle_detected": result.cycle_detected,
        "failed_urls": list(result.failed_urls.keys()),
        "validation_time_ms": result.elapsed_time_ms,
    }


# Run the validation
supply_chain_report = asyncio.run(validate_supply_chain(garment_dpp))
print(f"Supply chain documents: {supply_chain_report['total_documents']}")
print(f"All valid: {supply_chain_report['all_valid']}")

Consumer Applications

Mobile App DPP Scanner

Parse and display DPP data in a consumer app.

from dppvalidator import ValidationEngine

engine = ValidationEngine()


def scan_dpp_qrcode(qr_data: str | dict) -> dict:
    """Process scanned DPP QR code data for mobile app display."""
    result = engine.validate(qr_data)

    if not result.valid:
        return {
            "success": False,
            "error": "Invalid product passport",
        }

    passport = result.passport
    subject = passport.credential_subject if passport else None

    return {
        "success": True,
        "product": {
            "name": getattr(subject, "name", "Unknown"),
            "description": getattr(subject, "description", ""),
        },
        "issuer": {
            "name": passport.issuer.name if passport else "Unknown",
            "verified": result.signature_valid or False,
        },
        "sustainability": extract_sustainability_info(subject),
        "valid_until": (
            passport.valid_until.isoformat()
            if passport and passport.valid_until
            else None
        ),
    }


def extract_sustainability_info(subject) -> dict:
    """Extract sustainability information for display."""
    if not subject:
        return {}

    scorecard = getattr(subject, "circularity_scorecard", None)
    materials = getattr(subject, "materials_provenance", []) or []

    return {
        "recycled_content": (
            f"{scorecard.recycled_content * 100:.0f}%"
            if scorecard and scorecard.recycled_content
            else "N/A"
        ),
        "recyclable": (
            f"{scorecard.recyclable_content * 100:.0f}%"
            if scorecard and scorecard.recyclable_content
            else "N/A"
        ),
        "materials": [
            {
                "name": m.name,
                "percentage": f"{(m.mass_fraction or 0) * 100:.0f}%",
                "recycled": m.recycled or False,
            }
            for m in materials
        ],
    }

Recycling & Waste Management

Material Identification for Sorting

Help recycling facilities identify materials from DPP data.

from dppvalidator import ValidationEngine

engine = ValidationEngine()

RECYCLABLE_MATERIALS = {
    "cotton",
    "wool",
    "silk",
    "linen",
    "hemp",
    "polyester",
    "nylon",
    "pet",
}

HAZARDOUS_INDICATORS = {"lead", "mercury", "cadmium", "pvc"}


def analyze_for_recycling(dpp_data: dict) -> dict:
    """Analyze DPP for recycling facility sorting."""
    result = engine.validate(dpp_data)

    if not result.valid:
        return {"error": "Invalid passport", "sortable": False}

    materials = dpp_data.get("credentialSubject", {}).get("materialsProvenance", [])

    analysis = {
        "sortable": True,
        "materials": [],
        "recyclable": True,
        "hazardous": False,
        "recommended_stream": "textile",
    }

    for mat in materials:
        name = mat.get("name", "").lower()
        fraction = mat.get("massFraction", 0)
        hazardous = mat.get("hazardous", False)

        analysis["materials"].append(
            {
                "name": mat.get("name"),
                "fraction": f"{fraction * 100:.1f}%",
                "recyclable": any(r in name for r in RECYCLABLE_MATERIALS),
                "hazardous": hazardous,
            }
        )

        if hazardous or any(h in name for h in HAZARDOUS_INDICATORS):
            analysis["hazardous"] = True
            analysis["recommended_stream"] = "special_handling"

    return analysis

Customs & Border Control

Import Compliance Verification

Verify DPP compliance for imports.

from dppvalidator import ValidationEngine
from dppvalidator.vocabularies import is_valid_hs_code, is_textile_hs_code

engine = ValidationEngine(
    strict_mode=True,
    verify_signatures=True,
)


def verify_import_compliance(dpp_data: dict, declared_hs_code: str) -> dict:
    """Verify DPP compliance for customs import."""
    result = engine.validate(dpp_data)

    checks = {
        "dpp_valid": result.valid,
        "signature_verified": result.signature_valid or False,
        "issuer": result.issuer_did,
        "hs_code_valid": is_valid_hs_code(declared_hs_code),
        "is_textile": is_textile_hs_code(declared_hs_code),
        "requires_dpp": False,
        "compliance_status": "pending",
    }

    # Textiles require DPP from 2027
    if checks["is_textile"]:
        checks["requires_dpp"] = True
        checks["compliance_status"] = "compliant" if result.valid else "non_compliant"
    else:
        checks["compliance_status"] = "exempt"

    return checks

Resale & Recommerce

Product Authentication

Authenticate products for resale platforms.

from dppvalidator import ValidationEngine

engine = ValidationEngine(verify_signatures=True)


def authenticate_for_resale(dpp_data: dict) -> dict:
    """Authenticate product for resale platform."""
    result = engine.validate(dpp_data)

    authentication = {
        "authentic": False,
        "confidence": "low",
        "details": {},
    }

    if not result.valid:
        authentication["reason"] = "Invalid passport structure"
        return authentication

    # Check signature
    if result.signature_valid:
        authentication["authentic"] = True
        authentication["confidence"] = "high"
        authentication["details"]["signature"] = {
            "verified": True,
            "issuer": result.issuer_did,
            "method": result.verification_method,
        }
    else:
        authentication["confidence"] = "medium"
        authentication["details"]["signature"] = {"verified": False}

    # Extract provenance for display
    passport = result.passport
    if passport:
        authentication["details"]["product"] = {
            "id": str(passport.id),
            "issuer": passport.issuer.name,
            "valid_from": (
                passport.valid_from.isoformat() if passport.valid_from else None
            ),
        }

    return authentication

Next Steps