PassportLabDéveloppeursIntégration webhook

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.

Signé HMAC-SHA256Protection anti-rejeu (±5 min)File d'attente ARQ asynchroneMoteur de mappage de champs

1. Provisionnement

  1. Dans le tableau de bord PassportLab, accédez à Intégrations.
  2. Cliquez sur Configurer le webhook dans la tuile Generic Webhook.
  3. Donnez un nom à l'intégration (p. ex. SAP S/4HANA Production).
  4. À 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.
  5. (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ébit60 requêtes / minute / intégration
Nombre max. d'enregistrements par appel10 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 (pendingprocessingcomplete / 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 :

ChampExempleSignification
source_path$.MaterialDescriptionJSONPath vers votre charge utile ERP. Notation par crochets ou par points, toutes deux prises en charge.
target_fieldproductNameChemin en notation pointée vers l'objet <code>passportData</code> du DPP.
transformtrim, 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

StatutSignificationAction à mener
401 — X-PassportLab-Timestamp manquantEn-tête de signature envoyé, pas d'horodatageAjoutez l'en-tête d'horodatage.
401 — Hors de la tolérance de 5 minutesDérive d'horloge > 5 minSynchronisez l'horloge de votre serveur ERP via NTP.
401 — Signature invalideL'empreinte HMAC ne correspond pasVérifiez le secret et que vous avez signé timestamp + "." + raw body.
400 — Le corps doit être {"records": [...]}Enveloppe de forme incorrecteAssurez-vous que le corps JSON utilise le tableau records.
403 — Non autorisé pour cette intégrationCookie Bearer d'une autre organisationUtilisez la signature HMAC à la place.
404 — Intégration introuvableintegration_id incorrect dans l'URLVérifiez le tableau de bord des intégrations.
413 — Max. 10 000 enregistrements / appelTrop d'enregistrementsRépartissez en plusieurs appels.
429 — Limite de débit atteinte> 60 requêtes / minute / intégrationRalentissez 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ômeCause probable
401 Signature mismatch à chaque foisVotre base de signature ne correspond probablement pas à f"{ts}." + raw_body. Affichez les deux et comparez les octets.
Fonctionne avec curl, échoue dans le codeCertains 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 videsVos 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 minuteVous 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.