Envoyez vos données produit vers PassportLab via webhook
Un point de terminaison HTTP signé pour diffuser des produits depuis n'importe quel ERP, PIM ou PLM. Aucune connexion utilisateur PassportLab requise — votre ERP authentifie chaque requête avec une signature HMAC-SHA256 et un horodatage récent.
1. Provisionnement
- Dans le tableau de bord PassportLab, accédez à Intégrations.
- Cliquez sur Configurer le webhook dans la tuile Generic Webhook.
- Donnez un nom à l'intégration (p. ex. SAP S/4HANA Production).
- À la création, une boîte de dialogue unique affiche l'URL du webhook et le secret de signature. Copiez les deux immédiatement — le secret n'est affiché qu'une seule fois.
- (Facultatif mais recommandé.) Ouvrez Règles de mappage sur la carte de l'intégration et associez les noms de champs de votre ERP aux champs du passeport DPP. Le bouton Test intégré affiche la sortie normalisée sur un exemple de charge utile.
2. Format de la requête
Méthode et en-têtes
POST {webhookUrl}
Content-Type: application/json
X-PassportLab-Timestamp: <unix epoch seconds>
X-PassportLab-Signature: sha256=<hex digest>Corps
{
"records": [
{ "name": "Widget Pro", "barcode": "01234567890123", ... },
{ "name": "Widget Lite", "barcode": "01234567890116", ... }
]
}Chaque élément de records est un objet libre — vos règles de mappage le transforment en passeport DPP. Si aucune règle n'est configurée, les enregistrements doivent déjà respecter la structure passportData du DPP.
Limites
| Limite de débit | 60 requêtes / minute / intégration |
|---|---|
| Nombre max. d'enregistrements par appel | 10 000 |
| Tolérance d'horodatage | ±5 minutes par rapport à l'heure du serveur |
3. Signature
Nous utilisons le schéma de signature de type Stripe : horodatage + point + corps, HMAC-SHA256, empreinte hexadécimale, préfixée par sha256=.
signing_base = <timestamp> + "." + <raw request body bytes>
signature = "sha256=" + HMAC-SHA256(secret, signing_base).hexdigest()Inclure l'horodatage dans la charge utile signée constitue une protection anti-rejeu : même si une requête valide fuite, elle ne peut pas être renvoyée en dehors de la fenêtre de 5 minutes.
import hashlib, hmac, json, time, requests
INTEGRATION_ID = "REPLACE_ME"
SECRET = "REPLACE_ME" # from your credential vault
BASE_URL = "https://api.passportlab.io"
records = [{"name": "Widget Pro", "barcode": "01234567890123"}]
body = json.dumps({"records": records}).encode("utf-8")
ts = str(int(time.time()))
sig = "sha256=" + hmac.new(
SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256
).hexdigest()
res = requests.post(
f"{BASE_URL}/api/v1/integrations/{INTEGRATION_ID}/webhook-ingest",
data=body,
headers={
"Content-Type": "application/json",
"X-PassportLab-Timestamp": ts,
"X-PassportLab-Signature": sig,
},
timeout=30,
)
res.raise_for_status()
print(res.json()) # → {"jobId": "...", "totalRecords": 1, "enqueued": true}4. Réponse et interrogation
Une requête réussie renvoie 202 Accepted :
{
"jobId": "f4c1f2c8-7a51-4e3b-8c12-9bb9d8f00111",
"totalRecords": 1,
"enqueued": true
}enqueued: true— la tâche a été transmise au worker ARQ.enqueued: false— Redis est injoignable ; la tâche s'exécute en ligne en secours. Fonctionnellement identique, mais plus lent pour les gros lots.
Interroger les résultats
GET {baseUrl}/api/v1/jobs/{jobId}Renvoie status (pending → processing → complete / partial / failed), des compteurs par enregistrement, et un tableau results à la fin du traitement.
5. Mappage des champs
Si la structure de la charge utile de votre ERP diffère du schéma DPP (ce qui est presque toujours le cas), définissez des règles de mappage dans le tableau de bord. Chaque règle comporte quatre champs :
| Champ | Exemple | Signification |
|---|---|---|
source_path | $.MaterialDescription | JSONPath vers votre charge utile ERP. Notation par crochets ou par points, toutes deux prises en charge. |
target_field | productName | Chemin en notation pointée vers l'objet <code>passportData</code> du DPP. |
transform | trim, upper, number, iso_date, regex:<p>:<r> | Transformation de valeur facultative. |
default | "DE" | Utilisé lorsque le chemin source est absent. |
6. Réponses d'erreur
| Statut | Signification | Action à mener |
|---|---|---|
| 401 — X-PassportLab-Timestamp manquant | En-tête de signature envoyé, pas d'horodatage | Ajoutez l'en-tête d'horodatage. |
| 401 — Hors de la tolérance de 5 minutes | Dérive d'horloge > 5 min | Synchronisez l'horloge de votre serveur ERP via NTP. |
| 401 — Signature invalide | L'empreinte HMAC ne correspond pas | Vérifiez le secret et que vous avez signé timestamp + "." + raw body. |
| 400 — Le corps doit être {"records": [...]} | Enveloppe de forme incorrecte | Assurez-vous que le corps JSON utilise le tableau records. |
| 403 — Non autorisé pour cette intégration | Cookie Bearer d'une autre organisation | Utilisez la signature HMAC à la place. |
| 404 — Intégration introuvable | integration_id incorrect dans l'URL | Vérifiez le tableau de bord des intégrations. |
| 413 — Max. 10 000 enregistrements / appel | Trop d'enregistrements | Répartissez en plusieurs appels. |
| 429 — Limite de débit atteinte | > 60 requêtes / minute / intégration | Ralentissez ou appelez moins fréquemment. |
7. Recommandations opérationnelles
Idempotence
PassportLab utilise le code DPP (dérivé du GTIN + numéro de série) comme identifiant unique. Renvoyer un enregistrement avec le même GTIN+numéro de série est ignoré, pas dupliqué — la réponse le marque skipped avec le motif "DPP code 'DPP-…' already exists". Peut être retenté sans risque en cas d'erreur transitoire.
Nouvelles tentatives
En cas de 502 / 503 / 504 ou de délais réseau, réessayez avec un backoff exponentiel (1 s, 2 s, 4 s, 8 s, plafonné à 30 s). Jusqu'à 3 tentatives suffisent généralement. Ne réessayez pas en cas de réponse 4xx — la requête échouera à nouveau.
Regroupement par lots
- Petits ERP (< 1 000 SKU) : envoyez le catalogue complet chaque nuit en un seul appel.
- ERP plus volumineux : n'envoyez que le delta (lignes modifiées depuis la dernière synchronisation), par lots de jusqu'à 1 000 enregistrements par requête.
8. Dépannage
| Symptôme | Cause probable |
|---|---|
401 Signature mismatch à chaque fois | Votre base de signature ne correspond probablement pas à f"{ts}." + raw_body. Affichez les deux et comparez les octets. |
| Fonctionne avec curl, échoue dans le code | Certains clients HTTP resérialisent le JSON avant l'envoi, modifiant les espaces. Signez toujours les octets exacts envoyés sur le réseau — calculez l'empreinte après JSON.stringify. |
| Les enregistrements arrivent, mais les DPP résultants ont des champs vides | Vos règles de mappage ne couvrent pas ces champs. Ouvrez l'éditeur de mappage des champs, collez un exemple, cliquez sur Test et vérifiez la sortie normalisée. |
| 429 une fois par minute | Vous envoyez un enregistrement par appel HTTP. Regroupez-les dans un seul POST avec records: [...]. |
Prêt à envoyer votre premier enregistrement ERP ?
Créez un compte PassportLab gratuit, configurez un webhook générique, et vos données circuleront en moins de 10 minutes.