Première date limite DPP de l'UE (Batteries): 130 jours Devenez conforme maintenant
Langue
EN DE FR IT ES NL PL BG CS DA EL ET FI HR HU LT LV MT PT RO SK SL SV
Produit
Fonctionnalités Après-vente Comment ça marche Démo Entreprise Tarifs
Secteurs
Tous les secteurs Textiles Électronique Batteries
Ressources
Blog Comparer les logiciels DPP Exigences par pays Évaluation de préparation Vérificateur d'allégations environnementales Téléchargements gratuits Glossaire
Entreprise
Partenaires Contact
Se connecter Commencer gratuitement
Développeurs / API REST

Référence de l'API

Tout MyProductPassport est accessible via une API REST authentifiée par clé : créez des produits, générez et publiez des passeports numériques de produit, envoyez des données de batterie en direct et vérifiez la conformité, directement depuis votre ERP, votre PIM ou votre pipeline de build.

v1 https://myproductpassport.eu/api/v1 Commencer gratuitement Spécification OpenAPI ↓

01 / Premiers pasAuthentification

Chaque requête est authentifiée par une clé API transmise comme jeton Bearer. Les clés se créent dans l'application, sous Clés API, ne s'affichent qu'une fois et sont stockées hachées ; chaque clé a ses propres autorisations, une liste d'adresses IP autorisées facultative et une date d'expiration facultative. Les clés peuvent être renouvelées sans interruption.

En-tête de requête
Authorization: Bearer pk_your_api_key
Sur toutes les offres. Les clés API peuvent être créées et utilisées sur toutes les offres, y compris la gratuite. L'offre détermine le nombre de requêtes qu'une clé peut faire par minute (ci-dessous) et le nombre de produits et de passeports que l'espace de travail peut contenir.
Mode test. Une clé de test (pk_test_...) exécute chaque appel exactement comme une clé live, avec la même validation, les mêmes identifiants et les mêmes réponses, puis l'annule : rien n'est enregistré, aucun e-mail ni webhook n'est envoyé et aucun fichier n'est conservé. Les réponses contiennent "test_mode": true et un en-tête X-MPP-Mode: test. Développez et testez une intégration sur vos données réelles, puis passez à une clé live.

Les autorisations sont accordées par clé, pour qu'une intégration n'obtienne que ce dont elle a besoin :

AutorisationAutorisations
products:readLire les produits
products:writeCréer, modifier et supprimer des produits
passports:readLire les passeports
passports:writeGénérer des passeports
passports:publishPublier et archiver des passeports
webhooks:manageCréer, tester et supprimer des points de terminaison webhook
items:readRead individual items and their history
items:writeAdd, update and flag individual items
aftersales:readRead owner registrations and service requests
aftersales:writeUpdate service requests and reply to customers

02 / Premiers pasLimites de requêtes

Les limites s'appliquent par clé et par minute et dépendent de l'offre :

PlanRequêtes / minute
Gratuit30
Micro60
E-Label60
Starter120
Professional300
Business600
Battery600

Chaque réponse contient les en-têtes X-RateLimit-Limit et X-RateLimit-Remaining. Au-delà de la limite, la réponse est 429 :

429 Too Many Requests
{ "error": "Rate limit exceeded.", "limit": 300, "retry_after": 60 }

03 / Premiers pasErreurs

Les erreurs sont renvoyées en JSON avec un code de statut classique. Les plus courantes :

StatutSignificationExemple de corps
401Clé absente, invalide, révoquée ou expirée{"error": "Invalid or revoked API key."}
403La clé n'a pas une permission, l'IP n'est pas sur la liste autorisée, ou le quota de l'offre est atteint{"message": "API key does not have 'products:write' permission."}
404La ressource n'existe pas dans votre espace de travail{"message": "Not found."}
422La validation a échoué{"message": "…", "errors": {"gtin": ["…"]}}
429Limite de requêtes dépassée{"error": "Rate limit exceeded."}

04 / Premiers pasPagination

Les endpoints de liste renvoient 25 éléments par page avec les objets links et meta standard. Passez ?page=2 pour parcourir la collection.

05 / Premiers pasConnecteur d'assistant IA (MCP)

Connectez Claude, Cursor ou tout assistant qui parle le Model Context Protocol, et demandez-lui simplement de créer des produits, de remplir des passeports à partir de ce que vous lui dites et de vérifier ce qui manque encore. Il utilise une clé API, avec ses permissions et sa limite de requêtes. Il peut créer des brouillons et remplir des champs ; il ne publie, n'archive et ne supprime jamais rien : cela reste entre vos mains dans l'application.

Adresse du serveur (Streamable HTTP)
https://myproductpassport.eu/api/mcp
Claude Code
claude mcp add --transport http myproductpassport https://myproductpassport.eu/api/mcp \
  --header "Authorization: Bearer pk_live_your_key"
Cursor (mcp.json)
{
  "mcpServers": {
    "myproductpassport": {
      "url": "https://myproductpassport.eu/api/mcp",
      "headers": { "Authorization": "Bearer pk_live_your_key" }
    }
  }
}
Claude Desktop et les autres clients qui lancent un serveur local
{
  "mcpServers": {
    "myproductpassport": {
      "command": "npx",
      "args": ["mcp-remote", "https://myproductpassport.eu/api/mcp", "--header", "Authorization: Bearer pk_live_your_key"]
    }
  }
}

Les outils proposés :

OutilCe qu'il fait
list_productsLes produits de l'espace de travail, du plus récent au plus ancien, 25 par page, avec leur secteur et leur dernier passeport.
get_productUn produit avec ses détails, son secteur, ses sections réglementaires et son dernier passeport.
list_sectorsLes modèles de secteur qu'un produit peut utiliser (textile, électronique, batteries, vin et plus), avec leurs identifiants. Le secteur d'un produit détermine les champs obligatoires de son passeport.
create_productAjoute un produit à l'espace de travail. Utilisez un sector_id issu de list_sectors. compliance_sections ajoute des sections réglementaires à son passeport : gpsr, epr, france, chemicals, eudr.
list_passportsLes passeports de l'espace de travail, du plus récent au plus ancien, 25 par page, avec leur statut (draft, published, archived), leur taux de complétude et leur adresse publique.
get_passportUn passeport : statut, version, taux de complétude, adresse publique et liens vers le code QR.
create_passportCrée un brouillon de passeport pour un produit. Il n'est pas publié : c'est une personne qui le publie dans l'application.
get_passport_fieldsCe que demande un passeport : les clés des champs obligatoires et facultatifs, le sens de chacun (libellé, description, exemple), les valeurs présentes et les champs obligatoires manquants.
update_passport_fieldsÉcrit des valeurs de champs sur un passeport en brouillon ou publié (un passeport publié est mis à jour sur place : même adresse, même code QR). Clés issues de get_passport_fields ; une chaîne vide supprime une valeur. N'écrire que des faits indiqués par l'utilisateur ou ses documents.
get_complianceLa complétude d'un passeport : pourcentage, statut et champs obligatoires encore manquants.
Essayez avec une clé de test. Avec une clé de test (pk_test_...), les modifications de l'assistant sont vérifiées puis annulées, pour voir ce qu'il ferait avant de lui confier une clé réelle.

06 / Points de terminaisonCompte

GET /me

Renvoie le compte authentifié, son offre d'abonnement et la part utilisée du quota de produits. Utile pour tester la connexion.

Requête
curl https://myproductpassport.eu/api/v1/me \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": {
    "id": 42,
    "name": "Jane Doe",
    "email": "[email protected]",
    "company_name": "Acme Ltd",
    "subscription_tier": "professional",
    "product_count": 128,
    "product_limit": 500,
    "passport_count": 96,
    "organization": {"id": 7, "name": "Acme Ltd"},
    "api_key": {"name": "ERP sync", "permissions": ["*"], "rate_limit_per_minute": 1000, "expires_at": null},
    "webhooks_available": true
  }
}

07 / Points de terminaisonProduits

GET /products nécessite products:read

Liste les produits de votre espace de travail, du plus récent au plus ancien, 25 par page. Chaque produit inclut son secteur et un résumé de son dernier passeport.

ParamètreTypeDescription
pageintegerNuméro de page.
Requête
curl "https://myproductpassport.eu/api/v1/products?page=1" \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": [
    {
      "id": 512,
      "name": "Alpine Merino Crew Sweater",
      "sku": "AM-CREW-01",
      "gtin": "05012345678900",
      "brand": "Northloom",
      "category": "textiles",
      "status": "active",
      "country_of_origin": "PT",
      "weight": 0.4,
      "weight_unit": "kg",
      "materials": [
        { "name": "Merino wool (RWS)", "percentage": 78 },
        { "name": "Recycled nylon (GRS)", "percentage": 20 },
        { "name": "Elastane", "percentage": 2 }
      ],
      "sector": { "id": 3, "name": "Textiles" },
      "latest_passport": {
        "id": 96, "version": 1,
        "status": "published", "compliance_percentage": 100
      },
      "created_at": "2026-08-14T09:21:00+00:00",
      "updated_at": "2026-09-01T16:02:11+00:00"
    }
  ],
  "links": { "next": null },
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
POST /products nécessite products:write

Crée un produit. Échoue avec 403 si le quota de produits de l'offre est épuisé.

ParamètreTypeDescription
namestringobligatoireNom du produit, jusqu'à 255 caractères.
skustringVotre SKU interne, jusqu'à 100 caractères.
gtinstringGTIN-8, 12, 13 ou 14 (chiffres uniquement).
brandstringMarque affichée sur le passeport public.
descriptionstringJusqu'à 2 000 caractères.
categorystringCatégorie en texte libre. Par défaut « general ».
sector_idintegerUn identifiant de secteur, qui sélectionne le modèle de champs du passeport.
country_of_originstringCode pays, par ex. « PT ».
weightnumberPoids net.
weight_unitstringL'une des valeurs kg, g, lb, oz. Par défaut kg.
materialsarrayObjets {name, percentage 0-100}.
has_packagingbooleanAjoute au passeport les champs du modèle Emballage (clés commençant par pkg_), sous le même QR code.
Requête
curl -X POST https://myproductpassport.eu/api/v1/products \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alpine Merino Crew Sweater",
    "sku": "AM-CREW-01",
    "gtin": "05012345678900",
    "sector_id": 3,
    "materials": [
      {"name": "Merino wool (RWS)", "percentage": 78},
      {"name": "Recycled nylon (GRS)", "percentage": 22}
    ]
  }'
Réponse
{
  "data": {
    "id": 513,
    "name": "Alpine Merino Crew Sweater",
    "sku": "AM-CREW-01",
    "status": "active",
    "sector": { "id": 3, "name": "Textiles" },
    "created_at": "2026-09-07T18:40:00+00:00"
  }
}
POST /products/bulk nécessite products:write

Crée jusqu'à 100 produits en un appel. Le lot entier est refusé avec 403 s'il dépasse votre quota de produits restant. Pour des catalogues de plusieurs milliers d'articles, appelez ce point de terminaison en boucle ou utilisez l'import CSV de l'application.

ParamètreTypeDescription
productsarrayobligatoireDe 1 à 100 objets produit avec les mêmes champs que « Créer un produit » (hors matériaux).
Requête
curl -X POST https://myproductpassport.eu/api/v1/products/bulk \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {"name": "PSL-BT-122000", "sku": "PSL-BT-122000", "sector_id": 5},
      {"name": "PSL-BT-123000", "sku": "PSL-BT-123000", "sector_id": 5}
    ]
  }'
Réponse
{
  "message": "2 product(s) created.",
  "products": [
    { "id": 514, "name": "PSL-BT-122000", "status": "active" },
    { "id": 515, "name": "PSL-BT-123000", "status": "active" }
  ]
}
GET /products/{id} nécessite products:read

Renvoie un produit avec son secteur et un résumé de son dernier passeport. 404 si l'id n'est pas dans votre espace de travail.

Requête
curl https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key"
PUT /products/{id} nécessite products:write

Met à jour partiellement un produit. N'envoyez que les champs à modifier ; la liste des champs est la même que pour Créer un produit.

Requête
curl -X PUT https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"brand": "Northloom"}'
DELETE /products/{id} nécessite products:write

Supprime un produit de façon logique (soft delete). Les passeports publiés du produit continuent de fonctionner, pour que les QR codes imprimés ne soient jamais orphelins.

Requête
curl -X DELETE https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key"
Réponse
{ "message": "Product deleted." }

08 / Points de terminaisonPasseports

GET /passports nécessite passports:read

Liste les passeports, du plus récent au plus ancien, 25 par page, avec un résumé du produit et tous les champs du passeport.

ParamètreTypeDescription
pageintegerNuméro de page.
Requête
curl https://myproductpassport.eu/api/v1/passports \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": [
    {
      "id": 96,
      "uuid": "36ff3776-d517-4228-8cde-9208136ea84a",
      "version": 1,
      "status": "published",
      "compliance_status": "compliant",
      "compliance_percentage": 100,
      "public_url": "https://myproductpassport.co.uk/p/36ff3776-…",
      "gs1_url": "https://myproductpassport.co.uk/01/05012345678900",
      "product": { "id": 512, "name": "Alpine Merino Crew Sweater", "sku": "AM-CREW-01" },
      "fields": [
        { "key": "material_composition", "value": "…", "verification_status": "verified" }
      ],
      "published_at": "2026-08-16T10:00:00+00:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
POST /products/{productId}/passports nécessite passports:write

Génère un passeport brouillon pour un produit, en préremplissant les champs à partir des données produit et du modèle du secteur. Renvoie le brouillon avec son score de conformité. Si le produit a déjà un passeport en ligne, renvoie 409 avec ce passeport : corrigez-le avec PUT /passports/{id}/fields, qui conserve son adresse et son code QR.

Requête
curl -X POST https://myproductpassport.eu/api/v1/products/512/passports \
  -H "Authorization: Bearer pk_your_key"
GET /passports/{id} nécessite passports:read

Renvoie un passeport avec son produit, ses champs, son URL publique et son GS1 Digital Link.

Requête
curl https://myproductpassport.eu/api/v1/passports/96 \
  -H "Authorization: Bearer pk_your_key"
POST /passports/{id}/publish nécessite passports:publish

Publie un brouillon de passeport et met en ligne sa page publique et son QR code. Seuls les brouillons peuvent être publiés ; tout autre statut renvoie 404.

Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/publish \
  -H "Authorization: Bearer pk_your_key"
POST /passports/{id}/archive nécessite passports:publish

Archive un passeport et retire sa page publique de la circulation.

Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/archive \
  -H "Authorization: Bearer pk_your_key"
POST /passports/bulk-publish nécessite passports:publish

Publie jusqu'à 50 brouillons de passeport en un appel et indique le résultat pour chacun, afin qu'un échec n'interrompe jamais le lot.

ParamètreTypeDescription
passport_idsarrayobligatoireDe 1 à 50 identifiants de passeport.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/bulk-publish \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"passport_ids": [96, 97, 98]}'
Réponse
{
  "published": 2,
  "failed": 1,
  "published_ids": [96, 97],
  "errors": [
    { "id": 98, "error": "Compliance below the publishing threshold." }
  ]
}
POST /passports/{id}/successor nécessite passports:write

Pour un produit préparé en vue du réemploi, réaffecté ou reconditionné, le règlement sur les batteries (article 77, paragraphe 7) impose un nouveau passeport lié à l'original. Cette opération crée un nouvel enregistrement produit et un passeport brouillon prérempli à partir du passeport publié et lié à celui-ci. L'original reste en ligne et les deux passeports affichent le lien. Publiez le nouveau avec POST /passports/{id}/publish.

ParamètreTypeDescription
stagestringobligatoireprepared_for_reuse, repurposed ou remanufactured.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/successor \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "stage": "repurposed" }'
Réponse
{
  "data": {
    "id": 131, "status": "draft", "version": 1,
    "lineage": {
      "stage": "repurposed",
      "original": { "id": 96, "url": "https://myproductpassport.co.uk/p/..." },
      "originals": [{ "passport_id": 96, "product_id": 40, "stage": "repurposed", "status": "published", "url": "https://myproductpassport.co.uk/p/..." }],
      "successors": []
    }
  }
}
GET /passports/{id}/fields nécessite passports:read

Renvoie les clés de champ demandées par le modèle du secteur du passeport (obligatoires et facultatives), les valeurs actuelles et les clés obligatoires encore manquantes. Utilisez-le pour construire le contenu de PUT /passports/{id}/fields.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/fields \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "passport_id": 96,
  "sector": "batteries",
  "compliance_percentage": 84,
  "required": ["battery_category", "carbon_footprint", "..."],
  "optional": ["energy_round_trip_efficiency", "..."],
  "missing_required": ["carbon_footprint_class", "recycled_content"],
  "values": { "battery_category": "Industrial", "...": "..." }
}
PUT /passports/{id}/fields nécessite passports:write

Écrit n'importe quel ensemble de valeurs de champ sur un passeport brouillon ou en ligne : l'ensemble complet de l'annexe XIII pour une batterie, les champs d'un modèle de secteur ou vos propres clés. N'envoyez que les clés à modifier ; une valeur nulle ou vide supprime le champ. Un passeport en ligne est mis à jour sur place, son adresse et son QR code ne changent pas et ses traductions automatiques sont régénérées. La conformité est recalculée. Cet appel ne publie pas un brouillon ; utilisez POST /passports/{id}/publish.

ParamètreTypeDescription
fieldsobjectobligatoireTable de correspondance clé de champ / valeur. Les clés sont composées de lettres minuscules, de chiffres et de tirets bas ; les valeurs peuvent atteindre 5 000 caractères. Jusqu'à 200 clés par appel.
Requête
curl -X PUT https://myproductpassport.eu/api/v1/passports/96/fields \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "carbon_footprint": "61.2 kg CO2e/kWh",
      "carbon_footprint_class": "C",
      "recycled_content": "Cobalt 16%, lithium 6%, nickel 6%, lead 0%"
    }
  }'
Réponse
{
  "message": "3 field(s) changed, 0 removed.",
  "changed": ["carbon_footprint", "carbon_footprint_class", "recycled_content"],
  "removed": [],
  "passport": { "id": 96, "status": "published", "compliance_percentage": 92 }
}
POST /passports/{id}/state-of-health nécessite passports:write

Transmet les données propres à cette batterie (annexe XIII, point 4, du règlement (UE) 2023/1542) à un passeport publié, pour les systèmes BMS et de gestion de flotte. Envoyez n'importe quel sous-ensemble des champs ci-dessous ; la conformité est revérifiée après la mise à jour. Ces valeurs ne sont affichées qu'aux visiteurs approuvés par le titulaire du passeport (article 77, paragraphe 2), jamais sur la page publique. capacity_fade, power_capability et internal_resistance sont enregistrés comme mesures actuelles de cette batterie (current_*), distinctes des valeurs d'origine du modèle.

ParamètreTypeDescription
state_of_healthstringpar ex. « 97 % à 412 cycles ».
state_of_certified_energystringÉnergie certifiée restante (batteries de véhicules électriques).
battery_statusstringoriginal, repurposed, re-used, remanufactured ou waste.
capacity_fadestringPerte de capacité à ce jour. Enregistrée sous current_capacity_fade.
power_capabilitystringPuissance actuelle. Enregistrée sous current_power_capability.
internal_resistancestringRésistance interne mesurée. Enregistrée sous current_internal_resistance.
use_datastringCycles, événements négatifs, température et état de charge, jusqu'à 5 000 caractères.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/state-of-health \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "state_of_health": "97% at 412 cycles",
    "capacity_fade": "3% from initial rated capacity"
  }'
Réponse
{
  "message": "2 field(s) updated.",
  "updated_fields": ["state_of_health", "current_capacity_fade"],
  "passport": { "id": 96, "status": "published", "compliance_percentage": 100 }
}
POST /passports/{id}/units nécessite passports:write

Chaque batterie doit avoir son propre passeport (règlement (UE) 2023/1542, article 77, paragraphe 1). Enregistrez jusqu'à 10 000 batteries d'un modèle en un appel, chacune avec son numéro de série (jusqu'à 20 lettres, chiffres, points, tirets ou traits de soulignement) et, en option, manufacturing_date, battery_status et ses données de l'annexe XIII, point 4. Les numéros de série existants sont mis à jour ; les valeurs omises sont conservées. Si le produit a un GTIN, l'adresse de chaque batterie est son GS1 Digital Link, /01/{gtin}/21/{serial}. Les données du point 4 ne sont visibles que par les personnes autorisées par le titulaire.

ParamètreTypeDescription
units[].serialstringobligatoireLe numéro de série de la batterie.
units[].manufacturing_datestringMois et année, par ex. "2026-09".
units[].battery_statusstringoriginal ou waste. Un changement de statut nécessite les valeurs mesurées lors de celui-ci (annexe XIII, point 4 a)) ; waste nécessite aussi responsible_party_type (producer, pro ou waste_operator), responsible_party_name et responsible_party_contact (article 77, paragraphe 7). recycled, avec recycled_at et recycler_name, met fin au passeport (article 77, paragraphe 8). Une batterie réaffectée, réemployée ou remanufacturée reçoit un nouveau passeport : POST /passports/{id}/units/{serial}/successor.
units[].state_of_healthstringÉgalement state_of_certified_energy, current_capacity_fade, current_power_capability, current_internal_resistance, remaining_capacity_ah, power_fade, internal_resistance_increase, round_trip_efficiency, round_trip_efficiency_fade, expected_lifetime_cycles_remaining, self_discharge_rate, ohmic_resistance et use_data.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/units \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"units": [{"serial": "KES-00001", "manufacturing_date": "2026-09", "state_of_health": "100%"}]}'
Réponse
{ "created": 1, "updated": 0, "skipped": 0, "errors": [] }
PATCH /passports/{id}/units/{serial} nécessite passports:write

Pour un système de gestion de batterie qui envoie les données d'une batterie : n'importe lesquels de battery_status, state_of_health, state_of_certified_energy, current_capacity_fade, current_power_capability, current_internal_resistance et use_data. Faites un GET sur le même chemin pour les lire, ou GET /passports/{id}/units pour la liste (per_page jusqu'à 500).

Requête
curl -X PATCH https://myproductpassport.eu/api/v1/passports/96/units/KES-00001 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"state_of_health": "96% at 412 cycles"}'
Réponse
{
  "data": { "serial": "KES-00001", "public_url": "https://myproductpassport.co.uk/01/05012345678900/21/KES-00001", "battery_status": "original", "data": { "state_of_health": "96% at 412 cycles" } }
}
GET /passports/{id}/units/{serial}/snapshots nécessite passports:read

L'annexe XIII, point 4 a), exige les valeurs de performance et de durabilité lors de la mise sur le marché de la batterie et lors d'un changement de statut. Ces mesures sont conservées telles quelles, quelles que soient les données envoyées ensuite ; envoyez record_snapshot: true avec un PATCH pour conserver également une mesure périodique.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/units/KES-00001/snapshots \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": [
    { "event": "placed_on_market", "status": "original", "values": { "state_of_health": "100%" }, "measured_at": "2026-09-26T09:00:00+00:00", "source": "api" },
    { "event": "status_change", "status": "waste", "values": { "remaining_capacity_ah": "71 Ah", "power_fade": "14%", "internal_resistance_increase": "22%", "expected_lifetime_cycles_remaining": "0" }, "measured_at": "2029-03-02T10:00:00+00:00", "source": "bms" }
  ]
}
POST /passports/{id}/units/{serial}/successor nécessite passports:write

Article 77, paragraphe 7 : une batterie préparée en vue du réemploi, réaffectée ou remanufacturée dispose d'un nouveau passeport lié à son original. Cette opération enregistre à nouveau la batterie, avec un nouveau numéro de série et un nouvel identifiant, sous un modèle de batterie de seconde vie de votre espace de travail (créé à partir de ce modèle s'il n'en existe pas encore), relie les deux et conserve les valeurs mesurées lors du changement. La batterie d'origine conserve son passeport. Complétez et publiez le modèle de seconde vie avec POST /passports/{id}/publish.

ParamètreTypeDescription
stagestringobligatoireprepared_for_reuse, repurposed ou remanufactured.
valuesobjectobligatoireLes valeurs mesurées lors du changement : au moins une valeur parmi remaining_capacity_ah ou current_capacity_fade, parmi current_power_capability ou power_fade, parmi current_internal_resistance ou internal_resistance_increase, ainsi que expected_lifetime_cycles_remaining (annexe IV, partie A).
serialstringLe nouveau numéro de série. Par défaut : le numéro de série d'origine suivi de -RU, -RP ou -RM.
measured_atstringDate à laquelle les valeurs ont été mesurées.
member_statestringCode à deux lettres de l'État membre où l'état de santé a été testé (article 73, paragraphe 1, point a)).
target_passport_idintegerUn modèle de seconde vie existant de ce modèle de batterie, sous lequel l'enregistrer.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/units/KES-00001/successor \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"stage": "repurposed", "values": {"remaining_capacity_ah": "82 Ah", "power_fade": "9%", "internal_resistance_increase": "15%", "expected_lifetime_cycles_remaining": "2000"}}'
Réponse
{
  "data": {
    "serial": "KES-00001-RP", "battery_status": "repurposed", "passport_id": 131,
    "lineage": { "originals": [{ "serial": "KES-00001", "passport_id": 96, "stage": "repurposed" }], "successors": [] }
  }
}
POST /passports/{id}/registry nécessite passports:write

Enregistre sur un passeport la soumission au registre DPP de l'UE et son résultat : statut, ID de corrélation, identifiant d'enregistrement renvoyé par le registre et lien facultatif vers une copie de sauvegarde hébergée par un prestataire de services DPP. L'enregistrement lui-même s'effectue dans le registre de la Commission (formulaire web ou envoi de fichier) ; ceci conserve le résultat avec le passeport. GET /passports/{id} renvoie le même bloc sous registry.

ParamètreTypeDescription
statusstringnot_submitted, submitted, registered ou failed.
product_groupstringGroupe de produits du registre, par exemple batteries.
granularitystringmodèle, lot ou article.
upistringIdentifiant unique de produit sous forme d'URL https. Par défaut, l'URL du passeport public.
correlation_idstringIdentifiant de corrélation attribué par le Registre lors de la soumission.
uristringIdentifiant d'enregistrement renvoyé par le registre.
backup_urlstringLien https vers la copie de sauvegarde hébergée par un prestataire de services DPP.
submitted_atdateDate de soumission.
registered_atdateDate d'enregistrement.
errorstringDescription de l'erreur d'une soumission échouée.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/registry \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "registered",
    "correlation_id": "7f3a2c1e-0b4d-4f8e-9a6b-2d1c3e4f5a6b",
    "uri": "urn:eu:dpp:reg:00000001",
    "registered_at": "2027-02-18"
  }'
Réponse
{
  "message": "Registry details updated.",
  "passport": {
    "id": 96,
    "registry": {
      "status": "registered",
      "upi": "https://myproductpassport.co.uk/p/552fbb4e-5d9a-41da-9050-cc9005d8b66b",
      "correlation_id": "7f3a2c1e-0b4d-4f8e-9a6b-2d1c3e4f5a6b",
      "uri": "urn:eu:dpp:reg:00000001",
      "registered_at": "2027-02-18T00:00:00+00:00"
    }
  }
}
GET /passports/{id}/qr nécessite passports:read

Le QR code du passeport sous forme de fichier : svg (par défaut), png (à vos couleurs, prêt à imprimer) ou pdf (planche d'étiquettes).

ParamètreTypeDescription
formatstringsvg | png | pdf
Requête
curl "https://myproductpassport.eu/api/v1/passports/96/qr?format=png" \
  -H "Authorization: Bearer pk_your_key" -o passport-96.png

09 / Points de terminaisonConformité

GET /passports/{passportId}/compliance nécessite passports:read

Effectue un contrôle de conformité en direct d'un passeport par rapport aux champs obligatoires de son secteur et indique exactement ce qui manque.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/compliance \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": {
    "passport_id": 96,
    "product_name": "Alpine Merino Crew Sweater",
    "status": "compliant",
    "percentage": 100,
    "completed_fields": 12,
    "total_fields": 12,
    "missing_fields": []
  }
}

10 / Points de terminaisonSecteurs

GET /sectors

Les secteurs dans lesquels un produit peut être classé : les secteurs système de la plateforme ainsi que ceux définis par votre espace de travail. Utilisez l'id pour créer des produits et les clés de champ pour écrire les champs du passeport.

Requête
curl https://myproductpassport.eu/api/v1/sectors \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": [
    {
      "id": 4,
      "slug": "batteries",
      "name": "Batteries",
      "system": true,
      "regulations_finalised": true,
      "deadline": "2027-02-18",
      "deadline_label": "18 Feb 2027",
      "required_fields": ["battery_category", "battery_weight", "..."],
      "optional_fields": ["energy_round_trip_efficiency", "..."]
    }
  ]
}

11 / Points de terminaisonDocuments

GET /products/{productId}/documents nécessite products:read

Déclarations de conformité, rapports d'essai et certificats joints au produit. Un document public est lié depuis chaque passeport publié du produit.

Requête
curl https://myproductpassport.eu/api/v1/products/512/documents \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": [
    {
      "id": 31,
      "product_id": 512,
      "filename": "declaration-of-conformity.pdf",
      "mime_type": "application/pdf",
      "file_size": 184322,
      "is_public": true,
      "processing_status": "completed",
      "public_url": "https://myproductpassport.co.uk/p/3f0c.../document/31",
      "created_at": "2026-09-22T10:12:00+00:00"
    }
  ]
}
POST /products/{productId}/documents nécessite products:write

Envoi multipart. PDF, Word, Excel, CSV, texte, PNG et JPEG jusqu'à 10 Mo, 20 au maximum par produit. Le texte est extrait en arrière-plan.

ParamètreTypeDescription
filefileobligatoireLe document.
is_publicbooleanL'afficher sur le passeport public (false par défaut).
Requête
curl -X POST https://myproductpassport.eu/api/v1/products/512/documents \
  -H "Authorization: Bearer pk_your_key" \
  -F "[email protected]" \
  -F "is_public=1"
PATCH /products/{productId}/documents/{id} nécessite products:write

Indique si le document est lié depuis le passeport public.

ParamètreTypeDescription
is_publicbooleanobligatoire
Requête
curl -X PATCH https://myproductpassport.eu/api/v1/products/512/documents/31 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"is_public": false}'
DELETE /products/{productId}/documents/{id} nécessite products:write

Supprime le fichier et son lien avec le passeport.

Requête
curl -X DELETE https://myproductpassport.eu/api/v1/products/512/documents/31 \
  -H "Authorization: Bearer pk_your_key"
Réponse
{ "message": "Document deleted." }

12 / Points de terminaisonChaîne d'approvisionnement

GET /products/{productId}/supply-chain nécessite products:read

Les étapes affichées sur le passeport du produit, dans l'ordre.

Requête
curl https://myproductpassport.eu/api/v1/products/512/supply-chain \
  -H "Authorization: Bearer pk_your_key"
PUT /products/{productId}/supply-chain nécessite products:write

Remplace toutes les étapes par la liste envoyée, dans l'ordre d'envoi. Envoyez une liste vide pour la vider. Types d'étape : raw_material, processing, manufacturing, assembly, packaging, distribution.

ParamètreTypeDescription
stepsarrayobligatoireJusqu'à 50 étapes.
steps[].step_typestringobligatoire
steps[].supplier_namestringobligatoire
steps[].supplier_locationstring
steps[].supplier_countrystringISO 3166-1 alpha-2.
steps[].lat / lngnumber
steps[].descriptionstring
steps[].certificationsarray
steps[].datedate
Requête
curl -X PUT https://myproductpassport.eu/api/v1/products/512/supply-chain \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"steps": [{"step_type": "raw_material", "supplier_name": "Merino Growers Co-op", "supplier_country": "NZ", "certifications": ["RWS"]}, {"step_type": "manufacturing", "supplier_name": "Northloom Mill", "supplier_location": "Biella", "supplier_country": "IT"}]}'

13 / Points de terminaisonTraductions

GET /passports/{id}/translations nécessite passports:read

Chaque valeur de champ traduite par langue, avec sa source : auto (automatique, générée à la publication) ou manuelle.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/translations \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": {
    "passport_id": 96,
    "available_locales": ["bg", "cs", "da", "de", "..."],
    "translations": {
      "de": {"care_instructions": {"value": "Kalt waschen", "source": "manual"}}
    }
  }
}
PUT /passports/{id}/translations/{locale} nécessite passports:write

Définit les traductions d'une langue, par clé de champ. Une traduction manuelle n'est jamais écrasée par la machine. Envoyez une chaîne vide pour en supprimer une.

ParamètreTypeDescription
fieldsobjectobligatoirefield_key : valeur traduite
Requête
curl -X PUT https://myproductpassport.eu/api/v1/passports/96/translations/de \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"care_instructions": "Kalt waschen, nicht bleichen"}}'
Réponse
{ "message": "1 translation(s) written, 0 removed.", "locale": "de", "written": 1, "removed": 0 }

14 / Points de terminaisonIntégrité et exports

GET /passports/{id}/integrity nécessite passports:read

Chaque état publié du passeport sous forme d'enregistrement chaîné par hachage et signé en Ed25519 : empreinte (SHA-256), valeur de chaîne et signature. Les clés publiques se trouvent à /.well-known/mpp-integrity-keys.json, afin que chacun puisse vérifier la chaîne.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/integrity \
  -H "Authorization: Bearer pk_your_key"
Réponse
{ "data": { "state": "intact", "hash_algorithm": "SHA-256", "signature_algorithm": "Ed25519", "records": [ { "sequence": 1, "event": "published", "content_hash": "8f3a...", "chain_hash": "c21e...", "signature": "MEUC...", "key_id": "3fa9c21e0b7d4a11" } ], "problems": [] } }
GET /passports/{id}/integrity/{sequence} nécessite passports:read

L'enregistrement complet tel qu'il a été signé, instantané inclus : ce qu'indiquait le passeport à ce moment précis, jusqu'au hachage de chaque fichier joint.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/integrity/1 \
  -H "Authorization: Bearer pk_your_key"
GET /passports/{id}/epcis nécessite passports:read

Le passeport sous forme de document GS1 EPCIS 2.0 JSON-LD : l'article mis en service, chaque étape de la chaîne d'approvisionnement en tant qu'observation, les batteries individuelles, et un passeport seconde vie en tant que transformation. Les identifiants sont des URI GS1 Digital Link lorsque le produit possède un GTIN.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/epcis \
  -H "Authorization: Bearer pk_your_key"

15 / Points de terminaisonDemandes fournisseur

POST /passports/{id}/supplier-requests nécessite passports:write

Envoie par e-mail à un fournisseur un lien privé pour renseigner les champs que vous choisissez, dans sa langue. Rien n'est ajouté au passeport tant qu'un membre de votre espace de travail ne l'a pas approuvé.

ParamètreTypeDescription
supplier_namestringobligatoire
supplier_emailstringobligatoire
field_keysarrayobligatoireClés de champs issues du modèle du passeport.
localestringLangue de l'e-mail et du formulaire, par ex. de.
due_atdateDate limite de réponse ; 14 jours si omise.
messagestring
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/supplier-requests \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"supplier_name": "Mei Chen", "supplier_email": "[email protected]", "field_keys": ["recycled_content_cobalt", "carbon_footprint"], "locale": "de"}'
GET /passports/{id}/supplier-requests nécessite passports:read

Chaque demande concernant le passeport, avec son statut.

Requête
curl https://myproductpassport.eu/api/v1/passports/96/supplier-requests \
  -H "Authorization: Bearer pk_your_key"
GET /supplier-requests/{id} nécessite passports:read

Une demande avec les réponses du fournisseur, sa note et les noms des fichiers joints.

Requête
curl https://myproductpassport.eu/api/v1/supplier-requests/12 \
  -H "Authorization: Bearer pk_your_key"

16 / Points de terminaisonAprès-vente

POST /passports/{id}/items nécessite items:write

Donnez aux articles d'un produit (tout secteur sauf les batteries, qui utilisent /units) leur propre numéro de série : chacun reçoit sa propre adresse et son QR code, un code d'authenticité caché pour son étiquette, et peut être enregistré par son propriétaire. Envoyez jusqu'à 10 000 articles, ou une plage. Avec un GTIN, l'adresse est le GS1 Digital Link /01/{gtin}/21/{serial}.

ParamètreTypeDescription
items[].serialstringobligatoireJusqu'à 20 lettres, chiffres, points, tirets ou traits de soulignement.
items[].batchstringLot, jusqu'à 20 caractères.
items[].manufactured_onstringDate de fabrication, AAAA-MM-JJ.
rangeobjectÀ la place de items : prefix, start, count, digits et batch, par exemple SN-00001 à SN-00500.
Requête
curl -X POST https://myproductpassport.eu/api/v1/passports/96/items \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"range": {"prefix": "SN-", "start": 1, "count": 500, "digits": 5, "batch": "B2026-10"}}'
Réponse
{ "created": 500, "updated": 0, "skipped": 0, "over_limit": 0, "errors": [] }
GET /passports/{id}/items/{serial} nécessite items:read

Un article avec son adresse, son statut, s'il est enregistré et jusqu'à quand court sa garantie, ses vérifications d'authenticité et son historique. Une clé avec items:write obtient aussi son code caché, pour l'impression. GET /passports/{id}/items les liste (filtres status et batch, per_page jusqu'à 500).

Requête
curl https://myproductpassport.eu/api/v1/passports/96/items/SN-00001 \
  -H "Authorization: Bearer pk_your_key"
Réponse
{
  "data": { "serial": "SN-00001", "status": "active", "url": "https://myproductpassport.co.uk/01/05012345678900/21/SN-00001", "registered": true, "warranty_ends_on": "2028-10-02", "events": [ { "type": "registered", "country": "IE", "at": "2026-10-03T09:12:00+00:00" } ] }
}
PATCH /passports/{id}/items/{serial} nécessite items:write

Passez status à stolen ou recalled et sa page avertit quiconque le scanne, avec votre status_note ; un article volé ne peut pas être enregistré. retired met sa page hors ligne. batch et manufactured_on peuvent aussi être modifiés.

ParamètreTypeDescription
statusstringactive, stolen, recalled ou retired.
status_notestringAffiché sur la page de l'article, jusqu'à 500 caractères.
Requête
curl -X PATCH https://myproductpassport.eu/api/v1/passports/96/items/SN-00001 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"status": "stolen", "status_note": "Reported stolen on 2 October 2026."}'
GET /owner-registrations nécessite aftersales:read

Les personnes qui ont enregistré vos produits : nom, e-mail, pays, date d'achat, revendeur, dates de garantie, et si elles ont accepté les actualités et offres (marketing_consent=1 ne liste que celles-ci). Enregistrements actifs par défaut ; status=pending, transferred ou ended pour les autres ; since= pour les changements après une date.

Requête
curl "https://myproductpassport.eu/api/v1/owner-registrations?marketing_consent=1&since=2026-10-01" \
  -H "Authorization: Bearer pk_your_key"
GET /service-requests nécessite aftersales:read

Réparations, demandes de garantie, reprises, pièces détachées et questions envoyées depuis vos passeports, les plus récentes d'abord, avec filtres status et type. GET /service-requests/{reference} ajoute la conversation.

Requête
curl "https://myproductpassport.eu/api/v1/service-requests?status=new" \
  -H "Authorization: Bearer pk_your_key"
POST /service-requests/{reference}/replies nécessite aftersales:write

Votre réponse est envoyée au client par e-mail avec un lien vers sa page de demande, dans sa langue. internal: true ajoute une note que seule votre équipe voit. PATCH /service-requests/{reference} avec un status la fait avancer (le client est prévenu quand elle est en cours, résolue ou fermée).

ParamètreTypeDescription
bodystringobligatoireLa réponse, jusqu'à 5 000 caractères.
internalbooleanUne note pour votre équipe au lieu d'une réponse.
statusstringnew, in_progress, waiting, resolved ou closed.
Requête
curl -X POST https://myproductpassport.eu/api/v1/service-requests/SR-7K3F9Q/replies \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"body": "A new lid is on its way today.", "status": "waiting"}'

17 / Points de terminaisonModifications en masse et images

PATCH /products/bulk-fields nécessite products:write

Définit une information produit ou un champ de passeport sur jusqu'à 5 000 produits. mode vaut set, fill (uniquement là où la valeur est vide) ou clear. Jusqu'à 100 produits sont mis à jour dans la requête ; les ensembles plus importants sont mis en file d'attente (202).

ParamètreTypeDescription
product_idsarrayobligatoire
targetstringobligatoireproduct | field
keystringobligatoire
valuestring
modestringset | fill | clear
Requête
curl -X PATCH https://myproductpassport.eu/api/v1/products/bulk-fields \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"product_ids": [12, 13, 14], "target": "field", "key": "warranty_period", "value": "10 years", "mode": "fill"}'
Réponse
{ "data": { "changed": 2, "skipped": 1, "errors": [] } }
POST /products/{id}/images nécessite products:write

Téléversement multipart d'un fichier JPG, PNG ou WebP (jusqu'à 15MB, 8 par produit). La première image sert d'image de couverture sur le passeport public.

ParamètreTypeDescription
imagefileobligatoire
altstringDescription de l'image.
Requête
curl -X POST https://myproductpassport.eu/api/v1/products/12/images \
  -H "Authorization: Bearer pk_your_key" \
  -F [email protected] -F alt="Front of the battery"
PUT /products/{id}/images/order nécessite products:write

Transmettez image_ids dans l'ordre souhaité ; la première devient l'image de couverture.

ParamètreTypeDescription
image_idsarrayobligatoire
Requête
curl -X PUT https://myproductpassport.eu/api/v1/products/12/images/order \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"image_ids": [31, 30]}'
DELETE /products/{id}/images/{imageId} nécessite products:write

Supprime l'image et son fichier.

Requête
curl -X DELETE https://myproductpassport.eu/api/v1/products/12/images/31 \
  -H "Authorization: Bearer pk_your_key"

18 / Points de terminaisonWebhooks

GET /webhooks nécessite webhooks:manage

Les endpoints enregistrés pour votre espace de travail. Les secrets n'y figurent pas ; récupérez un endpoint pour voir son secret.

Requête
curl https://myproductpassport.eu/api/v1/webhooks \
  -H "Authorization: Bearer pk_your_key"
POST /webhooks nécessite webhooks:manage

Enregistre une URL HTTPS publique pour un ou plusieurs événements. La réponse inclut le secret de signature. Les hôtes privés ou internes sont refusés.

ParamètreTypeDescription
urlstringobligatoire
eventsarrayobligatoireL'un des événements listés ci-dessous.
Requête
curl -X POST https://myproductpassport.eu/api/v1/webhooks \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://erp.acme.example/mpp", "events": ["passport.published", "product.updated"]}'
Réponse
{
  "data": {
    "id": 3,
    "url": "https://erp.acme.example/mpp",
    "events": ["passport.published", "product.updated"],
    "is_active": true,
    "failure_count": 0,
    "secret": "9f1c...64 hex characters...",
    "created_at": "2026-09-22T10:12:00+00:00"
  }
}
GET /webhooks/{id} nécessite webhooks:manage

Requête
curl https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key"
PUT /webhooks/{id} nécessite webhooks:manage

Modifiez l'URL ou les événements, ou suspendez-le puis réactivez-le. La réactivation remet le compteur d'échecs à zéro ; un point de terminaison est suspendu automatiquement après 10 livraisons échouées consécutives.

ParamètreTypeDescription
urlstring
eventsarray
is_activeboolean
Requête
curl -X PUT https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"is_active": true}'
POST /webhooks/{id}/test nécessite webhooks:manage

Met en file d'attente un envoi webhook.test pour vérifier votre récepteur et votre code de signature.

Requête
curl -X POST https://myproductpassport.eu/api/v1/webhooks/3/test \
  -H "Authorization: Bearer pk_your_key"
Réponse
{ "message": "Test delivery queued." }
GET /webhooks/{id}/deliveries nécessite webhooks:manage

Envois récents, du plus récent au plus ancien, avec le statut HTTP renvoyé par votre endpoint et les 500 premiers caractères de sa réponse.

ParamètreTypeDescription
per_pageintegerJusqu'à 100.
Requête
curl https://myproductpassport.eu/api/v1/webhooks/3/deliveries \
  -H "Authorization: Bearer pk_your_key"
DELETE /webhooks/{id} nécessite webhooks:manage

Requête
curl -X DELETE https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key"
Réponse
{ "message": "Webhook endpoint deleted." }

19 / ÉvénementsWebhooks

Au lieu d'interroger régulièrement l'API, enregistrez un endpoint webhook dans l'application (page Webhooks, disponible à partir de l'offre Starter) et MyProductPassport enverra du JSON en POST à votre URL au fil des événements :

ÉvénementDéclenché quand
product.createdUn produit est créé (application, API ou import CSV)
product.updatedUn produit est mis à jour
product.deletedUn produit est supprimé
passport.createdUn passeport est généré
passport.publishedUn passeport est publié
passport.archivedUn passeport est archivé
supplier_request.submittedUn fournisseur envoie les informations que vous avez demandées
owner.registeredUn propriétaire confirme son enregistrement
owner.transferredUn article passe à un nouveau propriétaire enregistré
service_request.createdUn client envoie une demande de service depuis un passeport
service_request.updatedUne demande de service reçoit une réponse ou un nouveau statut
item.status_changedUn article est signalé volé, rappelé ou hors service, ou rétabli
item.verification_failedUne lecture sécurisée échoue, les codes erronés s'accumulent, ou un numéro de série est vu à trop d'endroits
webhook.testVous envoyez un envoi de test depuis l'application

Chaque livraison est une enveloppe JSON : un identifiant de livraison (le même identifiant est renvoyé lors des nouvelles tentatives, pour dédoublonner), l'événement, le numéro de tentative, un horodatage et les données de l'événement. Les événements de passeport contiennent l'uuid et l'URL publique du passeport, ce qui évite le plus souvent une seconde requête :

Corps de la livraison
{
  "id": 8123,
  "event": "passport.published",
  "attempt": 1,
  "created_at": "2026-09-22T10:12:00+00:00",
  "data": {
    "passport_id": 96,
    "uuid": "3f0c8f1e-...",
    "version": 2,
    "status": "published",
    "public_url": "https://myproductpassport.co.uk/p/3f0c8f1e-...",
    "product_id": 512,
    "product": {"id": 512, "name": "Alpine Merino Crew Sweater", "sku": "NL-AMC-001", "gtin": "5012345678900"}
  }
}

Les en-têtes contiennent le nom de l'événement, l'id d'envoi, un horodatage Unix et une signature HMAC du corps brut, pour que vous puissiez vérifier qu'il vient de nous et rejeter les rejeux :

En-têtes de la livraison
Content-Type: application/json
User-Agent: MyProductPassport-Webhooks/1.0
X-MPP-Event: passport.published
X-MPP-Delivery: 8123
X-MPP-Timestamp: 1790084320
X-MPP-Signature: sha256=<hex hmac of the raw body, keyed with your endpoint secret>

Répondez par un code 2xx dans les 10 secondes. Toute autre réponse est réessayée cinq fois sur environ 90 minutes (30 s, 1 min, 5 min, 15 min, 1 h) ; après 10 échecs consécutifs, le point de terminaison est suspendu jusqu'à ce que vous le réactiviez.

Vérifier (PHP)
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $endpointSecret);
abort_unless(hash_equals($expected, $request->header('X-MPP-Signature')), 401);