Con un abbonamento Verìd PRO, l'app invia i dati letti dalla CIE al tuo endpoint HTTPS. Questa pagina descrive il contratto tecnico: richiesta, payload, header, autenticazione e comportamento dell'app.
Al termine di ogni lettura (e dopo la Passive Authentication on-device),
Verìd effettua una richiesta HTTP POST con corpo JSON verso
l'URL configurato dall'operatore nelle impostazioni. I dati non
passano mai per server intermediari: l'app parla direttamente con il
tuo endpoint.
Il titolare del trattamento dei dati ricevuti è l'operatore che configura il webhook. Prima di ogni invio, l'app mostra all'utente destinazione e campi trasmessi e richiede consenso esplicito.
Nell'app, in Impostazioni → Webhook (richiede Verìd PRO):
Authorization: Bearer.Token e segreto si generano direttamente in app e si esportano in un file JSON da configurare sul tuo server: i due lati devono avere gli stessi valori.
POST /webhook HTTP/1.1
Host: gestionale.tuodominio.it
Content-Type: application/json; charset=utf-8
User-Agent: Verid-CIE-Reader
Authorization: Bearer <token>
X-Verid-Timestamp: 1782740547
X-Verid-Signature: sha256=9fa2...uL
Gli header Authorization e X-Verid-* sono presenti
solo se hai configurato rispettivamente token e segreto HMAC.
anagrafica e documento sono sempre presenti.
I campi non disponibili sulla carta (es. telephone, profession)
sono inclusi come null — non omessi. Gli array (placeOfBirth,
address) possono essere vuoti se il dato non è presente.
sessionRef, raw e photoPng compaiono
solo se le relative opzioni sono attive.
{
"source": "verid-cie-reader",
"sessionRef": "VRD-7H2K9-A2",
"anagrafica": {
"firstName": "MARIO",
"lastName": "ROSSI",
"gender": "M",
"dateOfBirth": "1985-04-12T00:00:00.000",
"placeOfBirth": ["ROMA", "RM"],
"fiscalCode": "RSSMRA85D12H501Z",
"address": ["VIA ROMA 1", "00100 ROMA RM"],
"telephone": null,
"profession": null
},
"documento": {
"number": "CA00000AA",
"issueDate": "2025-04-12T00:00:00.000",
"expiryDate": "2035-04-11T00:00:00.000",
"nationality": "ITA",
"country": "ITA",
"authority": "COMUNE DI ROMA"
},
// solo se "Includi DG grezzi" è attivo
"raw": {
"dg1": "Yn...", "dg2": "...",
"dg11": "...", "dg12": "...", "sod": "..."
},
// solo se "Includi la foto" è attivo
"photoPng": "iVBORw0KGgo..."
}
| Campo | Tipo | Note |
|---|---|---|
source | string | Sempre "verid-cie-reader". Permette di distinguere la sorgente lato server. |
sessionRef | string? | Presente solo se il QR di sessione è attivo e scansionato (vedi §08). |
anagrafica.dateOfBirth | string | ISO 8601. Data completa da DG11 se disponibile, altrimenti da MRZ. |
anagrafica.fiscalCode | string? | Da DG11 se disponibile, altrimenti dal campo optional data MRZ. Può essere null. |
anagrafica.placeOfBirth / address | string[] | Righe già ripulite dai separatori MRZ. Array vuoto se assente. |
raw.* | string (base64) | Byte DER dei Data Group. dg2 contiene la foto biometrica (JPEG2000). |
photoPng | string (base64) | Foto del titolare convertita in PNG. |
Il payload base (solo anagrafica e documento) pesa poche centinaia di byte. Abilitare la foto o i DG grezzi può portarlo a decine di KB: tienilo presente per i timeout del tuo server e i log.
| Header | Presente | Valore |
|---|---|---|
Content-Type | sempre | application/json; charset=utf-8 |
User-Agent | sempre | Verid-CIE-Reader |
Authorization | se token configurato | Bearer <token> |
X-Verid-Timestamp | se segreto configurato | Timestamp Unix in secondi |
X-Verid-Signature | se segreto configurato | sha256=<hex> |
Se hai configurato un segreto, ogni richiesta è firmata con HMAC-SHA256. L'algoritmo è:
"{X-Verid-Timestamp}.{corpo grezzo}" — timestamp (stringa) + punto + il body HTTP esatto, non ri-serializzato.sha256=.hash_equals (PHP) o timingSafeEqual (Node.js) per evitare timing attack.X-Verid-Timestamp sia entro ±5 minuti dall'ora corrente per mitigare i replay.Usa sempre il corpo grezzo della richiesta per il calcolo della firma, non il JSON ri-serializzato: qualsiasi differenza di spaziatura o ordinamento invaliderebbe la firma.
Se hai configurato un token, l'header Authorization arriva come
Bearer <token>. Estrai il valore dopo Bearer
e confrontalo con il token atteso usando un confronto a tempo costante.
Rispondi 401 se non corrisponde.
Token e firma HMAC sono indipendenti e complementari: puoi usarne uno, entrambi o nessuno. Per la massima sicurezza usa entrambi.
sessionRef)
Per collegare una lettura a una pratica del tuo gestionale, genera un QR dal
tuo sistema con un identificativo (es. l'ID di un ordine o di un cliente).
L'operatore lo scansiona prima della lettura e il valore torna nel payload
come sessionRef.
sessionRef non compare nel payload.
Verìd esegue la Passive Authentication on-device: verifica
l'integrità dei Data Group, la firma del SOD e la catena verso la CSCA italiana.
Il risultato (authentic / notAuthentic / notEvaluable)
è mostrato all'utente nell'app ma non è incluso nel payload webhook
nella versione attuale.
Se vuoi ri-verificare la Passive Authentication lato server, attiva
Includi DG grezzi: riceverai in raw i byte DER
(base64) di dg1, dg2, dg11,
dg12 e sod. La verifica lato server segue lo
standard ICAO 9303.
raw.dg2 contiene la foto biometrica (JPEG2000). Attiva i DG
grezzi solo se il tuo flusso ne ha effettivo bisogno e hai una base
giuridica adeguata per trattare questo dato.
Il pulsante "Invia un test" nelle impostazioni invia una richiesta di prova al tuo endpoint (con gli stessi header di produzione, inclusi token e firma se configurati) con questo payload:
{
"source": "verid-cie-reader",
"test": true,
"message": "Test di connettività dal pannello Verìd."
}
Puoi riconoscerlo dal campo "test": true e ignorarlo o loggarlo
separatamente. Rispondere con un 2xx conferma all'app che
l'endpoint è raggiungibile e le credenziali sono corrette.
L'app attende la risposta per un massimo di 20 secondi (15 per il test di connettività). Allo scadere del timeout, o in caso di errore di rete, l'invio è considerato fallito. Non ci sono retry automatici: l'utente vede il messaggio di errore e può riprovare manualmente.
| Codice risposta | Cosa vede l'utente nell'app |
|---|---|
200–299 | «Dati inviati correttamente.» |
401 / 403 | «Il server ha rifiutato i dati. Controlla token e segreto.» |
404 | «Indirizzo non trovato. Controlla l'URL del webhook.» |
408 / 429 | «Il server è occupato. Riprova tra poco.» |
5xx | «Il tuo server ha avuto un problema. Riprova più tardi.» |
| Timeout / rete | «Impossibile raggiungere il server. Controlla la connessione.» |
Il corpo della risposta non viene letto dall'app: puoi restituire un JSON vuoto o un messaggio descrittivo a tua scelta — non ha effetto sulla UI.
localhost e hostname *.local (rete locale mDNS, per i test).
Per gli IP privati (10.x, 192.168.x, …) è richiesto HTTPS oppure un hostname
.local: HTTP verso un IP privato viene bloccato dall'app.
== o ===: un attaccante può dedurre quanti
caratteri sono corretti misurando il tempo di risposta. Usa funzioni dedicate:
hash_equals() in PHP, timingSafeEqual() in Node.js,
o l'equivalente nel tuo linguaggio.
X-Verid-Timestamp contiene l'ora Unix in secondi del momento
in cui l'app ha firmato la richiesta. Rifiuta le richieste con timestamp più
vecchio di 5 minuti (o futuro di oltre 1 minuto): questo blocca i replay,
cioè un attaccante che cattura una richiesta legittima e la reinvia in seguito.