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.
1. Provisioning
- Nella dashboard PassportLab, vai su Integrazioni.
- Fai clic su Configura webhook nel riquadro Generic Webhook.
- Assegna un'etichetta all'integrazione (es. SAP S/4HANA Produzione).
- 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.
- (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 frequenza | 60 richieste / minuto / integrazione |
|---|---|
| Record massimi per chiamata | 10 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 (pending → processing → complete / 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:
| Campo | Esempio | Significato |
|---|---|---|
source_path | $.MaterialDescription | JSONPath nel payload del tuo ERP. Supportate sia la notazione a parentesi quadre sia quella puntata. |
target_field | productName | Percorso puntato nell'oggetto <code>passportData</code> del DPP. |
transform | trim, upper, number, iso_date, regex:<p>:<r> | Trasformazione del valore facoltativa. |
default | "DE" | Utilizzato quando il percorso di origine è assente. |
6. Risposte di errore
| Stato | Significato | Cosa fare |
|---|---|---|
| 401 — X-PassportLab-Timestamp mancante | Header di firma inviato, nessun timestamp | Aggiungi l'header del timestamp. |
| 401 — Fuori dalla tolleranza di 5 minuti | Deriva dell'orologio > 5 min | Sincronizza l'orologio del tuo server ERP tramite NTP. |
| 401 — Firma non corrispondente | Il digest HMAC non corrisponde | Verifica il segreto e di aver firmato timestamp + "." + raw body. |
| 400 — Il corpo deve essere {"records": [...]} | Involucro dalla forma errata | Assicurati che il corpo JSON usi l'array records. |
| 403 — Non autorizzato per questa integrazione | Cookie Bearer di un'altra organizzazione | Usa invece la firma HMAC. |
| 404 — Integrazione non trovata | integration_id errato nell'URL | Controlla la dashboard delle integrazioni. |
| 413 — Massimo 10 000 record / chiamata | Troppi record | Suddividi in più chiamate. |
| 429 — Limite di frequenza raggiunto | > 60 richieste / minuto / integrazione | Rallenta 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
| Sintomo | Causa probabile |
|---|---|
401 Signature mismatch ogni volta | La 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 codice | Alcuni 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 vuoti | Le 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 minuto | Stai 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.