PassportLabSviluppatoriIntegrazione webhook

Invia i dati prodotto a PassportLab tramite webhook

Un endpoint HTTP firmato per trasmettere prodotti da qualsiasi ERP, PIM o PLM. Nessun login utente PassportLab richiesto — il tuo ERP autentica ogni richiesta con una firma HMAC-SHA256 e un timestamp aggiornato.

Firmato HMAC-SHA256Protezione anti-replay (±5 min)Coda ARQ asincronaMotore di mappatura campi

1. Provisioning

  1. Nella dashboard PassportLab, vai su Integrazioni.
  2. Fai clic su Configura webhook nel riquadro Generic Webhook.
  3. Assegna un'etichetta all'integrazione (es. SAP S/4HANA Produzione).
  4. Alla creazione, una finestra di dialogo mostrata una sola volta rivela l'URL del webhook e il segreto di firma. Copia subito entrambi — il segreto viene mostrato una sola volta.
  5. (Facoltativo ma consigliato.) Apri Regole di mappatura sulla scheda dell'integrazione e associa i nomi dei campi del tuo ERP ai campi del passaporto DPP. Il pulsante Test integrato mostra l'output normalizzato su un payload di esempio.

2. Formato della richiesta

Metodo e header

POST {webhookUrl}
Content-Type: application/json
X-PassportLab-Timestamp: <unix epoch seconds>
X-PassportLab-Signature: sha256=<hex digest>

Corpo

{
  "records": [
    { "name": "Widget Pro", "barcode": "01234567890123", ... },
    { "name": "Widget Lite", "barcode": "01234567890116", ... }
  ]
}

Ogni elemento di records è un oggetto libero — le regole di mappatura lo trasformano in un passaporto DPP. Se non sono configurate regole, i record devono già corrispondere alla struttura passportData del DPP.

Limiti

Limite di frequenza60 richieste / minuto / integrazione
Record massimi per chiamata10 000
Tolleranza del timestamp±5 minuti rispetto all'ora del server

3. Firma

Utilizziamo lo schema di firma in stile Stripe: timestamp + punto + corpo, HMAC-SHA256, digest esadecimale, preceduto da sha256=.

signing_base = <timestamp> + "." + <raw request body bytes>
signature    = "sha256=" + HMAC-SHA256(secret, signing_base).hexdigest()

Includere il timestamp nel payload firmato costituisce una protezione anti-replay: anche se una richiesta valida viene intercettata, non può essere reinviata al di fuori della finestra di 5 minuti.

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. Risposta e polling

Una richiesta riuscita restituisce 202 Accepted:

{
  "jobId": "f4c1f2c8-7a51-4e3b-8c12-9bb9d8f00111",
  "totalRecords": 1,
  "enqueued": true
}
  • enqueued: true — il job è stato passato al worker ARQ.
  • enqueued: false — Redis non è raggiungibile; il job viene eseguito in linea come fallback. Funzionalmente identico, ma più lento per batch di grandi dimensioni.

Interrogare i risultati

GET {baseUrl}/api/v1/jobs/{jobId}

Restituisce status (pendingprocessingcomplete / partial / failed), contatori per record e, al completamento, un array results.

5. Mappatura dei campi

Se la struttura del payload del tuo ERP differisce dallo schema DPP (quasi sempre il caso), definisci le regole di mappatura nella dashboard. Ogni regola ha quattro campi:

CampoEsempioSignificato
source_path$.MaterialDescriptionJSONPath nel payload del tuo ERP. Supportate sia la notazione a parentesi quadre sia quella puntata.
target_fieldproductNamePercorso puntato nell'oggetto <code>passportData</code> del DPP.
transformtrim, upper, number, iso_date, regex:<p>:<r>Trasformazione del valore facoltativa.
default"DE"Utilizzato quando il percorso di origine è assente.

6. Risposte di errore

StatoSignificatoCosa fare
401 — X-PassportLab-Timestamp mancanteHeader di firma inviato, nessun timestampAggiungi l'header del timestamp.
401 — Fuori dalla tolleranza di 5 minutiDeriva dell'orologio > 5 minSincronizza l'orologio del tuo server ERP tramite NTP.
401 — Firma non corrispondenteIl digest HMAC non corrispondeVerifica il segreto e di aver firmato timestamp + "." + raw body.
400 — Il corpo deve essere {"records": [...]}Involucro dalla forma errataAssicurati che il corpo JSON usi l'array records.
403 — Non autorizzato per questa integrazioneCookie Bearer di un'altra organizzazioneUsa invece la firma HMAC.
404 — Integrazione non trovataintegration_id errato nell'URLControlla la dashboard delle integrazioni.
413 — Massimo 10 000 record / chiamataTroppi recordSuddividi in più chiamate.
429 — Limite di frequenza raggiunto> 60 richieste / minuto / integrazioneRallenta o chiama con minore frequenza.

7. Indicazioni operative

Idempotenza

PassportLab utilizza il codice DPP (derivato da GTIN + numero di serie) come identificatore univoco. Reinviare un record con lo stesso GTIN+numero di serie viene ignorato, non duplicato — la risposta lo contrassegna come skipped con motivo "DPP code 'DPP-…' already exists". Sicuro da ritentare in caso di errori transitori.

Tentativi ripetuti

In caso di 502 / 503 / 504 o timeout di rete, ritenta con backoff esponenziale (1s, 2s, 4s, 8s, con limite massimo di 30s). Generalmente fino a 3 tentativi sono sufficienti. Non ritentare in caso di risposte 4xx — la richiesta fallirà di nuovo.

Raggruppamento in batch

  • ERP di piccole dimensioni (< 1 000 SKU): invia il catalogo completo ogni notte in un'unica chiamata.
  • ERP più grandi: invia solo il delta (righe modificate dall'ultima sincronizzazione), suddiviso in gruppi fino a 1 000 record per richiesta.

8. Risoluzione dei problemi

SintomoCausa probabile
401 Signature mismatch ogni voltaLa base della firma nel tuo codice probabilmente non corrisponde a f"{ts}." + raw_body. Stampa entrambe e confronta i byte.
Funziona con curl, fallisce nel codiceAlcuni client HTTP riserializzano il JSON prima dell'invio, modificando gli spazi bianchi. Firma sempre i byte esatti inviati sulla rete — calcola il digest dopo JSON.stringify.
I record arrivano ma i DPP risultanti hanno campi vuotiLe tue regole di mappatura non coprono quei campi. Apri l'editor di mappatura dei campi, incolla un esempio, fai clic su Test e controlla l'output normalizzato.
429 una volta al minutoStai inviando un record per ogni chiamata HTTP. Raggruppali in un unico POST con records: [...].

Pronto a inviare il tuo primo record ERP?

Avvia un account PassportLab gratuito, configura un webhook generico e vedrai i dati fluire in meno di 10 minuti.