Vai al contenuto principale
Attività di autenticazione e relativa consegna dei webhook, che dipende dalla release, sono documentate in Eventi di autenticazione e webhook. Non registrare tipi di evento di autenticazione non elencati con l’API di destinazione attuale.

Panoramica

I webhook sono il modo in cui Didit ti invia aggiornamenti in tempo reale ogni volta che una sessione di verifica, una sessione aziendale, un utente del fornitore, un’azienda del fornitore o una transazione cambia stato. Associare una o più destinazioni agli eventi che ti interessano ti permette di reagire nel momento in cui un risultato è pronto, di norma entro pochi secondi dal completamento del flusso da parte dell’utente sottoposto a verifica. I webhook sono il pattern di integrazione consigliato. Il polling di GET /v3/session/{id}/decision/ è supportato come soluzione di ripiego, ma è più lento, richiede più richieste e salta eventi come data.updated, transaction.status.updated e le modifiche a livello di entità, che vengono emessi solo tramite webhook. Considera la consegna dei webhook come la fonte di verità e ricorri al polling solo all’avvio a freddo o per la riconciliazione. Questo capitolo della lezione di integrazione dell’Academy di Didit riprende dalla panoramica dei webhook. La lezione dell’Academy sull’integrazione tratta i webhook a partire da 3:12: aggiunta di una destinazione, scelta degli eventi e il segreto di firma che verificherai più avanti.
Utenti Cloudflare / WAF. Didit consegna i webhook dall’IP statico 18.203.201.92 con User-Agent: DiditWebhook/2.0 +https://didit.me. Se il tuo perimetro di rete blocca i client sconosciuti, consenti questo IP in Security > WAF > Tools > IP Access Rules e scegli Consenti per l’hostname che riceve i webhook.

Tipi di evento

Usa il valore esatto nell’array subscribed_events di una destinazione webhook. Non esiste un carattere jolly: elenca ogni famiglia che vuoi ricevere, e puoi distribuire gli eventi su più destinazioni. I valori di questa tabella sono l’insieme completo degli eventi a cui è possibile iscriversi: non esistono session.status.updated, kyc.completed o simili. L’unica altra consegna effettuata da Didit è la callback kyb.registry_search.resolved non firmata, che viene inviata alla webhook_url indicata per ogni richiesta in POST /v3/kyb/search/, mai a una destinazione webhook.
Il menu Business Console > API & Webhooks > Try Webhook invia payload completi per ciascuno di questi eventi (approvati, rifiutati, in revisione, nomi Unicode, KYC/KYB, entità, attività e transazione). Usalo per verificare il tuo endpoint prima di andare in produzione.

Struttura del payload

Struttura generale

Tutti i webhook condividono la stessa struttura. I campi vengono sempre serializzati con sort_keys=True e separatori compatti (, / :), così lo stesso payload produce la stessa firma su entrambi i lati. Per gli eventi di sessione (status.updated, data.updated su sessioni regolari e aziendali) la struttura contiene inoltre:

Esempio della struttura di sessione

L’oggetto decision ha lo stesso schema restituito da GET /v3/session/{id}/decision/. Per il riferimento canonico dei campi di ogni funzionalità (ogni proprietà di id_verifications[], aml_screenings[] e così via) vedi Modelli di dati. Non duplichiamo volutamente qui le tabelle dei campi per funzionalità, così lo schema esiste in un solo punto.

Array plurali V3 (importante)

All’interno di decision, ogni risultato per funzionalità è un array plurale, così un singolo workflow può includere più istanze della stessa funzionalità (ad esempio più controlli di identità su diversi documenti):
Ogni elemento contiene un node_id che corrisponde al grafo del workflow, oltre a un status per funzionalità. Non leggere i campi singolari della V2 (id_verification, nfc, liveness, face_match, phone, email, poa, aml, ip_analysis, database_validation): compaiono solo se una destinazione è esplicitamente configurata con webhook_version: "v2". I risultati della firma elettronica si trovano in signatures[], presenti solo se il workflow include un passaggio di firma elettronica: un elemento per firmatario, con il firmatario, la conferma del codice, il certificato, il timestamp, gli hash e i percorsi di download di ogni documento, e il PDF delle prove. Non esiste un evento di firma separato: status.updated indica quando leggerli. Vedi il report della firma elettronica. I risultati della Verifica bancaria si trovano in bank_verifications[], un elemento per ogni passaggio di Verifica bancaria. Il method di ogni elemento indica come è stato verificato il conto: open_banking (accesso alla banca), account_lookup (controllo del conto), oppure un metodo di ripiego basato su statement o microdeposits; è null finché non viene valutato un conto. Quando la persona sceglie Continue without your bank, continued_without_bank è true e continuation indica il motivo. In quel caso method è none, a meno che in precedenza non sia stato valutato un tentativo: vedi Quando la persona non può verificare il proprio conto bancario. Un conto verificato tramite controllo del conto non legge dati finanziari, quindi financial_data.not_collected elenca i saldi, le transazioni o i redditi richiesti dal passaggio. Vedi Metodi di verifica bancaria.

Blocco Investigator

Una decision V3 per una sessione utente o aziendale include anche investigator: l’ultima revisione della sessione da parte di Investigator, oppure null se la sessione non ne ha mai avuta una. Le funzionalità di raccolta documenti, Documenti KYB e Document AI, non hanno un array plurale dedicato: compaiono nell’elenco features[] della decisione come { "feature": "DOCUMENT_AI", "node_id": "…" } (una voce per nodo). Vedi Document AI. Le decisioni di Verifica degli utenti includono anche un singolo oggetto biometric_consent: indica se la sessione richiedeva un consenso biometrico esplicito, il trigger, lo status della risposta e le relative evidenze. status: "pending" con reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK" indica che un SDK nativo precedente alla versione 4.10.0 ha acquisito un volto senza il passaggio di consenso. Vedi Consenso biometrico.

Chiavi del metodo di Verifica dell’identità

Ogni elemento di id_verifications[] indica quale metodo di Verifica dell’identità lo ha prodotto, così un gestore può ramificare la logica in base alle evidenze effettivamente ricevute: I gestori esistenti continuano a funzionare senza modifiche: una sessione con documento imposta verification_method a document e lascia il resto a null. I tipi di ciascun campo sono in Modelli di dati.

Sessione wallet approvata (status.updated)

Payload degli eventi delle entità

Gli stati delle entità sono ACTIVE, FLAGGED o BLOCKED. user.data.updated e business.data.updated mantengono il campo status e aggiungono un array changed_fields e una mappa changes di { field: { previous, current } }. Gli eventi business.* usano vendor_business_id al posto di vendor_user_id.

Payload degli eventi di transazione

I webhook delle transazioni usano la stessa infrastruttura di distribuzione e lo stesso involucro, ma identificano la transazione anziché una sessione:
action_required è null, oppure l’azione richiesta all’utente ancora da eseguire (type wallet_ownership o verification_session, con il suo url), descritta in Azioni richieste all’utente. Le nuove transazioni hanno come valore predefinito APPROVED. Se una regola, una blocklist o un workflow modifica lo stato durante la creazione, il payload iniziale transaction.created riflette lo stato finale. transaction.status.updated ha la stessa struttura, con lo status aggiornato. Gli stati delle transazioni sono APPROVED, IN_REVIEW, DECLINED o AWAITING_USER; severity è UNKNOWN / LOW / MEDIUM / HIGH / CRITICAL e direction è INBOUND / OUTBOUND. transaction.created e transaction.status.updated vengono inviati solo per le applicazioni in produzione. Gli scambi Travel Rule in sandbox emettono comunque travel_rule.status.updated con environment: sandbox.

Callback della ricerca nel registro KYB

Il flusso asincrono POST /v3/kyb/search/ invia un payload extra che non è un evento di destinazione: quando passi un webhook_url alla richiesta di ricerca, Didit invia una callback kyb.registry_search.resolved a quell’URL non appena il registro restituisce il risultato. Si differenzia dai webhook di destinazione in tre modi:
  • È non firmata: non ci sono intestazioni X-Signature*. Didit la contrassegna con X-Didit-Unsigned-Callback: true; per validarla, confronta request_id con l’ID restituito dalla richiesta di ricerca.
  • Il nome dell’evento è in event_type (non in webhook_type) e non sono presenti application_id né environment.
  • timestamp e created_at sono interi epoch, come in altri webhook, ma diversi dal created_at ISO dell’endpoint di ricerca.
La callback segue la stessa politica di nuovo tentativo dei webhook di destinazione: i nuovi tentativi aggiornano timestamp e restano non firmati. Per lo schema completo della lista dei candidati, vedi KYB Registry API.

Verifica della firma

Ogni webhook è firmato con HMAC-SHA256 usando secret_shared_key della destinazione. Vengono inviate tre intestazioni di firma, così puoi scegliere quella più adatta al tuo stack: Intestazioni che Didit invia sempre: Per 24 ore dopo la rotazione del segreto di firma di una destinazione, le consegne includono anche X-Signature-Previous, X-Signature-V2-Previous e X-Signature-Simple-Previous (vedi Rotazione del segreto di firma).

Rotazione del segreto di firma

Ruoti il segreto di firma di una destinazione nella Business Console. Per 24 ore dopo la rotazione, ogni consegna a quella destinazione include altre tre intestazioni, generate con il segreto sostituito: Un handler che accetta una corrispondenza su un’intestazione di firma o sulla corrispondente intestazione -Previous continua a verificare mentre distribuisci il nuovo segreto: il vecchio segreto corrisponde all’intestazione -Previous, il nuovo a quella regolare. Gli esempi di codice qui sotto fanno proprio questo. Distribuisci il nuovo segreto entro 24 ore, perché dopo questo periodo solo il nuovo segreto consente la verifica. previous_secret_expires_at su GET /v3/webhook/destinations/{destination_uuid}/ indica quando terminano le 24 ore. I nuovi tentativi e i reinvii vengono firmati di nuovo con il segreto corrente della destinazione al momento dell’invio, e includono le intestazioni -Previous solo finché durano le 24 ore. Se ruoti di nuovo entro le 24 ore, il segreto più vecchio viene ritirato subito: attraverso le intestazioni -Previous continua a essere verificato solo il segreto che era corrente fino alla nuova rotazione, per 24 ore a partire dalla nuova rotazione. Le intestazioni -Previous esistono solo per le destinazioni webhook. Il secret_shared_key a livello di applicazione, che firma il webhook_url legacy, non prevede alcun periodo di sovrapposizione: ruotarlo con rotate_secret_key su PATCH /v3/webhook/ invalida immediatamente il vecchio segreto.

X-Signature-Simple è deprecato

X-Signature-Simple autentica l’involucro, non il payload. La sua stringa canonica copre solo timestamp, session_id, status e webhook_type. Non copre decision, né resubmit_info, metadata, vendor_data o event_id. Una richiesta in cui decision è stata riscritta, lasciando intatti questi quattro campi, supera comunque la verifica di X-Signature-Simple.La garanzia è ancora più debole per gli eventi che non hanno affatto session_id. Gli eventi di transazione (transaction_id, txn_id, amount, score) ed entità (vendor_user_id, vendor_business_id) firmano "{timestamp}::{status}:{webhook_type}", che non identifica a quale transazione o entità si riferisce l’evento: due transazioni diverse segnalate con lo stesso status nello stesso secondo hanno la stessa X-Signature-Simple. Anche gli eventi travel_rule.status.updated, workflow.compliance_changed e transaction_rule_suggestions.created non hanno status, quindi firmano "{timestamp}:::{webhook_type}", per esempio "{timestamp}:::travel_rule.status.updated".Se X-Signature-Simple è l’unica intestazione che controlli, considera non attendibile tutto ciò che sta al di fuori di questi quattro campi e recupera di nuovo il record dall’API: GET /v3/session/{session_id}/decision/ per una sessione, GET /v3/transactions/{transaction_id}/ per una transazione. L’API è il server di riferimento.
Questo è un vincolo di compatibilità, non qualcosa che possiamo correggere sul posto. La stringa canonica a quattro campi è un contratto a livello di protocollo: ogni ricevitore che verifica X-Signature-Simple ricalcola esattamente questi quattro campi, quindi cambiare ciò che l’intestazione firma li farebbe smettere silenziosamente di funzionare durante la verifica. Coprire il body richiede anche una forma canonica specificata del JSON che entrambe le parti riproducano byte per byte, e Didit ne fornisce già una come X-Signature-V2. Invece di aggiungere una seconda variante che copra il body con regole di canonicalizzazione proprie, l’intestazione resta invariata e viene deprecata a favore delle varianti esistenti che coprono l’intero payload. Cosa significa per te:
  • A livello di protocollo non cambia nulla. X-Signature-Simple continua a essere inviato in ogni consegna, calcolato allo stesso modo. I verificatori esistenti continuano a funzionare, e annunceremo con largo anticipo qualsiasi rimozione.
  • Le nuove integrazioni devono usare X-Signature-V2. È sicuro per il middleware e copre l’intero payload.
  • Se non puoi passare da X-Signature-Simple, verificalo, poi recupera il record dall’API invece di leggerlo dal body del webhook.

Perché tre varianti?

Alcuni framework web (parser del body di Express, middleware di Django, API gateway) ricodificano silenziosamente il JSON prima che il tuo handler lo legga. Se il body originale conteneva "José" e il middleware lo riscrive come "José", i byte cambiano anche se i dati sono identici. X-Signature allora fallisce. X-Signature-V2 è calcolato da una forma JSON canonica (chiavi ordinate, separatori compatti, Unicode non escapato) che quasi tutti i middleware riproducono in modo deterministico. La deprecata X-Signature-Simple ripiega sulla firma di una piccola stringa indipendente dal parser quando anche questo fallisce. Poiché firma solo quella stringa breve e mai il body, non può garantire il body.

Ordine di verifica consigliato

  1. Prova prima X-Signature-V2. Ricodifica JSON.parse(body) con le chiavi ordinate e Unicode preservato, poi calcola HMAC-SHA256(secret, canonical) e confronta l’intestazione con il risultato usando timingSafeEqual.
  2. Se la V2 non corrisponde e puoi leggere i byte grezzi, prova X-Signature contro HMAC-SHA256(secret, rawBody).
  3. Solo se entrambe falliscono, ripiega sulla X-Signature-Simple, deprecata, contro HMAC-SHA256(secret, "{timestamp}:{session_id}:{status}:{webhook_type}"). Questo autentica solo l’involucro: considera il decision nel body come non attendibile e recuperalo di nuovo da GET /v3/session/{session_id}/decision/ prima di agire.
In ogni passaggio, quando è presente l’intestazione -Previous corrispondente, accetta una corrispondenza con una qualsiasi delle due intestazioni (vedi Rotazione del segreto di firma). In tutti i casi, rifiuta ogni richiesta più vecchia di 5 minuti (abs(now - X-Timestamp) > 300) per proteggerti dai replay.

Politica di nuovo tentativo

Se il tuo endpoint risponde con un 5xx o un 404, Didit effettua fino a 2 nuovi tentativi con backoff esponenziale:
  • Primo nuovo tentativo: circa 1 minuto dopo il primo errore.
  • Secondo nuovo tentativo: circa 4 minuti dopo il primo nuovo tentativo.
Dopo il secondo nuovo tentativo la consegna viene scartata. Ogni tentativo di consegna (iniziale più nuovi tentativi) viene registrato come voce separata nella Business Console, nella scheda Consegne della destinazione, così puoi rieseguire o ispezionare qualsiasi tentativo. Ogni tentativo nel registro di consegna di una destinazione riporta un numero attempt: 1 per la prima consegna di un evento, e un numero superiore di uno rispetto a quello del tentativo ripetuto, per ogni nuovo tentativo o reinvio. I nuovi tentativi automatici vanno all’URL a cui è stato inviato il primo tentativo, anche se nel frattempo hai modificato url della destinazione. Un reinvio manuale va all’URL attuale della destinazione, quindi correggere l’URL corregge anche il reinvio. Altre regole di consegna da conoscere:
  • La richiesta HTTP in uscita scade dopo 5 secondi.
  • Didit blocca le consegne verso URL privati o localhost come protezione SSRF e non segue mai i redirect. Usa un endpoint HTTPS pubblico che risponda direttamente.
  • Un url di destinazione che contiene una barra inversa grezza, un carattere di controllo o più di una @ nell’authority viene rifiutato come malformato: un URL del genere non può essere creato e uno esistente non può essere riconsegnato o rieseguito. Usa un URL semplice https://host/path con al massimo una sezione userinfo (per URL di webhook in stile basic auth).
  • 2xx è considerato un successo. Timeout ed errori di connessione sono ritentabili (compaiono come 504/503 nel registro di consegna); le risposte 3xx e 4xx diverse da 404 non vengono ritentate.
  • Al nuovo tentativo Didit ricalcola le firme con un nuovo X-Timestamp, così la coppia timestamp/firma è sempre coerente.
  • I nuovi tentativi e i reinvii sono firmati con il segreto di firma corrente della destinazione nel momento in cui vengono inviati.

Ordine di consegna

Didit non garantisce l’ordine in cui i webhook ti arrivano. Ogni consegna viene accodata separatamente e un nuovo tentativo arriva minuti dopo il primo tentativo, quindi un status.updated per Approved può arrivarti prima di uno precedente per In Progress. Progetta il tuo ricevitore tenendo conto di questo:
  • Tratta un webhook come un segnale che qualcosa è cambiato. Quando l’ordine conta, chiama GET /v3/session/{session_id}/decision/ e agisci in base allo status attuale.
  • Non lasciare mai che un evento più vecchio sovrascriva uno stato più recente: confronta il created_at dell’evento con l’ultimo che hai memorizzato per quel record e ignora quello più vecchio.
  • Usa event_id per riconoscere le ripetizioni, perché resta invariato tra i nuovi tentativi.
Didit accoda gli eventi di un trasferimento Travel Rule in un ordine prestabilito, descritto in Travel Rule exchange status changed, ma un nuovo tentativo può comunque cambiare l’ordine in cui arrivano.

Configurare una destinazione

Puoi gestire le destinazioni dalla Business Console > API & Webhooks oppure tramite la Management API.
1

Crea la destinazione

Chiama POST /v3/webhook/destinations/ (oppure fai clic su Aggiungi destinazione nella console) con una label, un url pubblico, una webhook_version ("v3") e un array subscribed_events che contiene ogni famiglia di eventi che questo endpoint deve ricevere. È richiesto almeno un evento e non esiste alcun wildcard.
2

Conserva il secret_shared_key

La risposta della creazione restituisce il secret_shared_key della destinazione. Conservalo insieme agli altri segreti del server: appartiene solo a questa destinazione ed è l’input di tutte e tre le varianti di firma HMAC-SHA256. GET /v3/webhook/destinations/{destination_uuid}/ lo restituisce di nuovo ai chiamanti con chiave API e agli utenti della console che possono leggere i webhook.
3

Implementa l'endpoint

Esponi una route POST HTTPS pubblica, leggi il body grezzo, verifica la firma (preferendo X-Signature-V2), controlla la finestra temporale del timestamp, poi smista in base a webhook_type. Restituisci 2xx appena hai accodato il lavoro: esegui le elaborazioni intensive in modo asincrono.
4

Verifica le ricezioni

Controlla la scheda Consegne della destinazione. I webhook funzionanti restituiscono 200 entro uno o due secondi. 5xx/404 attiva la politica di nuovo tentativo di Didit; le consegne che continuano a fallire vengono scartate dopo il secondo nuovo tentativo.
5

Itera con Try Webhook

Usa gli scenari Try Webhook della console per far passare il tuo endpoint attraverso payload approvati, rifiutati, in revisione, KYB, entità, attività e transazioni prima di attivare il traffico di produzione.
Funzionalità di test dei webhook di Didit nella Business Console

Invia webhook di test direttamente dalla Business Console per verificare il tuo endpoint prima di andare in produzione.

Puoi creare tutte le destinazioni che ti servono. Uno schema comune è una destinazione per consumatore: ad esempio eventi KYC verso il tuo servizio di autenticazione, eventi KYB verso il tuo servizio operativo di compliance, transazioni verso la tua coda antifrode. Ogni destinazione ha il proprio segreto, la propria versione e il proprio elenco di sottoscrizioni, quindi un segreto ruotato o un deploy difettoso su un consumatore non influisce sugli altri.

Esempi di codice

Per garantire la sicurezza del tuo endpoint webhook, verifica l’autenticità delle richieste in arrivo usando il secret_shared_key della destinazione.
Usa X-Signature-V2. È la variante più resistente alla ricodifica da parte dei middleware e autentica completamente il body (incluso decision).

Node.js / Express (consigliato: X-Signature-V2)

Se puoi leggere i byte grezzi prima che qualsiasi parser li tocchi, la variante originale X-Signature funziona allo stesso modo, ma firma il body grezzo. La manteniamo nella sezione legacy qui sotto per completezza.

Python / FastAPI (consigliato: X-Signature-V2)

PHP / Laravel (consigliato: X-Signature-V2)

I valori predefiniti di JSON in PHP non riproducono la forma canonica. Quattro di essi vanno sovrascritti, e se ne manca anche solo uno cambiano i byte firmati, quindi il digest non corrisponde mai: La trappola degli oggetti vuoti è quella che fa più danni. I payload di Didit contengono regolarmente mappe vuote come risk_view.countries.risk_scores, risk_view.crimes.risk_scores e risk_view.custom_list, quindi un round-trip associativo rompe la firma già nelle sessioni approvate ordinarie, e non solo in qualche caso raro.
Ci sono altre due cose da sapere:
  • I float con valore intero non richiedono alcuna gestione speciale in PHP. Didit li serializza come interi (100.0 → 100), e json_encode di PHP scrive un float intero allo stesso modo, quindi non serve alcun passaggio shortenFloats, a differenza dell’esempio Node.js sopra.
  • Mantieni serialize_precision a -1 (il valore predefinito da PHP 7.1). Se il tuo host lo imposta a 17, json_encode scrive 87.42 come 87.420000000000002 e ogni verifica di X-Signature-V2 fallisce.
Se non riesci a far coincidere la forma canonica, verifySignatureRaw qui sopra è l’alternativa più semplice: $request->getContent() di Laravel restituisce i byte originali, quindi X-Signature funziona finché nulla davanti a PHP ricodifica il body. È esattamente il caso per cui X-Signature-V2 è progettato, ed è per questo che V2 viene provato per primo.

Test

Non serve eseguire una verifica completa per testare il tuo endpoint.
  • Da Business Console > API & Webhooks > Try Webhook, scegli uno scenario (ad esempio approved_full_features, declined_face_mismatch, in_review_aml_hit, business_session_approved, transaction_created, activity_created, user_status_updated) e invia un webhook completo all’URL della tua destinazione.
  • Ogni scenario è firmato con le stesse tre intestazioni di firma e la stessa codifica canonica del traffico di produzione, inclusi dati di test Unicode (approved_kyc_with_unicode), così puoi verificare che X-Signature-V2 funzioni attraverso il tuo middleware. Le consegne di test contengono dati di esempio e sono contrassegnate con un’intestazione aggiuntiva X-Didit-Test-Webhook: true (e con il suffisso (Test) su User-Agent), così puoi evitare che incidano sullo stato di produzione.
  • Riproduci qualsiasi consegna storica dalla scheda Consegne di una destinazione se devi fare il debug di una regressione.
Per i test smoke end-to-end, esegui una verifica reale tramite un workflow di test nella tua applicazione: i webhook risultanti usano la stessa struttura, le stesse intestazioni e la stessa politica di nuovi tentativi degli scenari Try Webhook.

Esempi

Sessione KYC approvata (status.updated)

Sessione rifiutata con avvisi (status.updated)

Sessione aziendale approvata (status.updated, KYB)

Transazione creata (transaction.created)

Stato dello scambio Travel Rule modificato (travel_rule.status.updated)

travel_rule_status assume uno dei 13 stati di scambio documentati in Travel Rule. rail è INTERNAL, TRP, GTR, TRUST, VERIFYVASP, SYGNA o EMAIL (stringa vuota finché non viene selezionato un canale, se non è stato possibile determinarne nessuno, e sempre per le registrazioni sunrise), oppure TEST_VASP per un trasferimento sandbox a cui ha risposto il Didit Test VASP, e direction è INBOUND o OUTBOUND. Un evento sandbox contiene "environment": "sandbox", e un evento TEST_VASP contiene anche test_vasp: true e test_vasp_scenario (lo scenario che ha risposto). Quando Didit crea una transazione per un trasferimento Travel Rule (una chiamata POST /v3/transactions/, una registrazione sunrise dopo il deposito, una richiesta TRP in entrata o la parte in entrata sul canale INTERNAL), invia prima l’evento transaction.created per quella transazione e poi gli eventi travel_rule.status.updated del trasferimento. Una regola che modifica lo stato della transazione durante questo passaggio può anche inviare transaction.status.updated prima di transaction.created, e una registrazione sunrise collegata a una transazione di deposito già creata non invia transaction.created. Ogni webhook viene consegnato, e in caso di errore sottoposto a un nuovo tentativo, in modo indipendente, quindi un evento sottoposto a un nuovo tentativo può arrivare dopo uno successivo: usa transaction_id come chiave nel tuo handler e rileggi la transazione quando ti serve lo stato attuale. Un trasferimento inviato tramite TRUST non riceve mai un evento COMPLETED, perché TRUST non restituisce nulla che Didit possa leggere: resta in AWAITING_COUNTERPARTY fino alla scadenza della conferma e poi termina come EXPIRED. Con GTR, VerifyVASP e Sygna Bridge, Didit legge dalla rete la risposta della controparte e l’evento la segue (vedi Reti Travel Rule).

Stato di conformità del workflow modificato (workflow.compliance_changed)

transition.from e transition.to sono uno dei seguenti valori: compliant, gaps_detected, pending_change, unknown_coverage o not_evaluated. severity è actionable quando sono state rilevate lacune, indicative per una modifica in attesa e informative quando le lacune sono state risolte. Didit invia un evento per ogni workflow che è cambiato.

Suggerimenti di regole per le transazioni creati (transaction_rule_suggestions.created)

kind è ADD per una nuova regola, TWEAK per la modifica di una regola esistente e DISABLE per disattivarne una. rule_id è null per ADD. open_count è il numero di suggerimenti ancora aperti dopo l’esecuzione, inclusi quelli nuovi. Le impostazioni dei suggerimenti sulle regole attivano o disattivano questo webhook; vedi Webhook delle transazioni.

Eventi dell’Investigator (investigator.*)

I dodici eventi investigator.* usano la stessa struttura comune (event_id, webhook_type, timestamp, created_at, application_id, environment) e gli stessi header di firma di ogni altro evento. Contengono solo id e cifre: mai un nome, un motivo digitato da un revisore, una narrazione o quanto scritto dall’utente finale. Non hanno session_id; l’elemento a cui si riferiscono è indicato in item.
provenance indica quale versione dell’Investigator ha scritto il report:
  • engine è la versione del motore dell’Investigator: un identificativo opaco di otto caratteri. Cambia ogni volta che cambia il motore, quindi due report con lo stesso engine sono stati scritti dallo stesso motore.
  • agent_version è la versione dell’agente.
  • policy_version è la versione della tua policy che il report ha seguito.
  • model_id è un alias obsoleto che contiene lo stesso valore di engine. Leggi engine al suo posto.
  • prompt_hash non viene più inviato.
item.kind indica il tipo di elemento (una sessione, una sessione aziendale, una transazione o un caso) e item.id il suo id. I timestamp che terminano con _at sono stringhe ISO 8601. Per iscriverti a questi eventi, elenca le stringhe esatte in subscribed_events, come per qualsiasi altro evento.

Stato dell’entità utente modificato (user.status.updated)

Sessione reinviata

Legacy: X-Signature con corpo grezzo

X-Signature viene ancora inviata con ogni consegna. È un HMAC-SHA256 calcolato sui byte esatti che Didit trasmette (json.dumps(..., sort_keys=True, separators=(",", ":"))). Usala solo quando puoi leggere il corpo grezzo prima che qualsiasi middleware lo modifichi.

Legacy: formato webhook V2

I campi seguenti si applicano solo quando una destinazione è fissata a webhook_version: "v2". Esiste anche un’impostazione ancora più vecchia, "v1" (una terza forma di decisione, al singolare), per le destinazioni create prima della V2: contatta il supporto prima di farvi affidamento. Le nuove integrazioni devono usare V3 (il valore predefinito), descritta sopra, che usa array al plurale.
Gli oggetti delle singole funzionalità sono gli stessi nelle due versioni: una destinazione V2 riceve esattamente gli stessi match_score, risk_score, score_breakdown, risk_view e review_status per ogni riscontro, oltre al score aggregato che riceve V3 (vedi report AML). Impostare la destinazione sulla V2 cambia la posizione del report AML all’interno di decision, non il suo contenuto. Se un consumatore a valle richiede ancora le strutture V2, crea una destinazione separata fissata a webhook_version: "v2" e mantieni i nuovi consumatori su V3.

Correlati

Ultima modifica il 7 novembre 2026