> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Widget proprietà wallet - Prova di controllo Travel Rule

> Widget ospitato che dimostra il controllo di un wallet crypto tramite firma di messaggi, Satoshi test, screenshot o autodichiarazione, per la Travel Rule.

Il widget di verifica della proprietà del wallet è una pagina ospitata che dimostra che uno dei tuoi clienti controlla un determinato indirizzo di wallet crypto. Ai sensi del TFR dell'UE, un VASP deve verificare la proprietà di un wallet in autocustodia (unhosted) prima di inviare o ricevere fondi da quel wallet, se l'importo supera la soglia sunrise. Il widget è lo strumento con cui Didit raccoglie questa prova, senza che tu debba sviluppare da zero i flussi di firma.

Una prova verificata contrassegna la corrispondente [voce della rubrica degli indirizzi wallet](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#rubrica-degli-indirizzi-wallet) come `is_ownership_verified: true`, il che consente a un [trasferimento Travel Rule](https://docs.didit.me/it/transaction-monitoring/travel-rule.md) collegato di uscire da `UNCONFIRMED_OWNERSHIP`.

## Quando Didit lo genera per te

Raramente hai bisogno di generare una sessione manualmente.
Quando `auto_wallet_verification` è attivo nelle tue [impostazioni Travel Rule](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#configurazione) (impostazione predefinita), Didit genera automaticamente una sessione del widget alla creazione della transazione, ogni volta che un trasferimento richiede la prova del controllo del wallet da parte dell'utente finale:

* Il trasferimento è in `UNCONFIRMED_OWNERSHIP`: il wallet della controparte è stato [dichiarato in autocustodia](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#wallet-in-autocustodia-dichiarati) al momento dell'invio.
* Il trasferimento è in uscita e si trova in `COUNTERPARTY_VASP_NOT_FOUND`: non è stato possibile identificare alcun VASP della controparte, quindi la prova della proprietà è l'unica via rimasta per il completamento.

La sessione generata automaticamente viene restituita nel blocco `action_required` della transazione (`type: "wallet_ownership"`, con l'`url` da aprire), e gli SDK la avviano automaticamente all'[invio lato client](https://docs.didit.me/it/transaction-monitoring/sdk-transaction-submission.md#azioni-richieste-all’utente).
I trasferimenti in entrata che Didit crea per te (una registrazione sunrise, una richiesta `TRP` in entrata o il ramo in entrata del canale `INTERNAL`) non ricevono mai una sessione generata automaticamente, anche quando finiscono in `UNCONFIRMED_OWNERSHIP`.
Genera manualmente una sessione con `POST /v3/travel-rule/widget-session/` quando vuoi pre-verificare un wallet prima che esista qualsiasi trasferimento, quando `auto_wallet_verification` è disattivato, oppure per uno di questi trasferimenti in entrata.

## Cosa dimostra

Il widget offre fino a quattro metodi di prova. Quali compaiono dipende da come hai creato la sessione e dalle tue [impostazioni Travel Rule](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#configurazione):

| Metodo | Come funziona | Quando viene offerto |
| - | - | - |
| `MESSAGE_SIGNING` | Il cliente firma con il suo wallet una stringa di challenge emessa da Didit. Supporta wallet EVM, Solana, Bitcoin e Tron (per Bitcoin: indirizzi legacy, SegWit annidato, SegWit nativo e Taproot). Didit verifica la firma rispetto all'indirizzo; se si firma con un account diverso da quello da verificare, la firma viene rifiutata con una chiara richiesta di cambio account. Anche gli account a smart contract EVM (smart wallet ERC-4337) possono firmare: Didit chiede al contratto dell'account, sulla chain dichiarata per il wallet, se la firma è valida (ERC-1271), e per un account non ancora distribuito verifica la firma ERC-6492 restituita dal wallet, senza distribuire l'account né inviare alcuna transazione. Gli account a smart contract vengono controllati su ogni chain EVM supportata. Vedi [Contratto di verifica per la firma del messaggio](#contratto-di-verifica-per-la-firma-del-messaggio) più avanti. I wallet installati nel browser del cliente vengono rilevati tramite i protocolli EIP-6963 e Wallet Standard, quindi ogni estensione compare come opzione di firma separata. L'abbinamento di un'app wallet mobile separata, ad esempio tramite codice QR, al momento non è disponibile. | Sempre, per le famiglie di chain supportate. |
| `SATOSHI_TEST` | Il cliente invia dal wallet un piccolo importo on-chain a un indirizzo di deposito che controlli tu. Il watcher di Didit verifica il mittente (per un account a smart contract EVM, l'account stesso, anche quando un bundler ERC-4337 invia la transazione), l'importo e la conferma del deposito on-chain, quindi completa automaticamente la prova una volta confermato - vedi [Contratto di verifica del test Satoshi](#contratto-di-verifica-del-test-satoshi) più avanti. | Solo quando passi un `satoshi_deposit_address` al momento della creazione e la chain è EVM, Bitcoin o Solana; quindi mai su una sessione creata automaticamente. |
| `SCREENSHOT` | Il cliente carica uno screenshot del wallet che mostra l'indirizzo (JPEG/PNG/WebP, fino a 10 MB). A differenza degli altri metodi, non viene mai verificato automaticamente: il tuo team di compliance lo esamina dalla coda di revisione degli screenshot ([`GET /v3/travel-rule/wallet-proofs/`](https://docs.didit.me/it/management-api/travel-rule/list-wallet-proofs)) e lo approva o lo rifiuta ([`POST .../decision/`](https://docs.didit.me/it/management-api/travel-rule/decide-wallet-proof)), oppure conferma il trasferimento dalla scheda **Travel Rule** della transazione nella console o tramite [`POST .../travel-rule/ownership/`](https://docs.didit.me/it/management-api/travel-rule/confirm-ownership) (per un trasferimento in `UNCONFIRMED_OWNERSHIP` o un trasferimento in entrata in attesa). | Solo quando `allow_screenshot_proof` è `true` nelle tue impostazioni. |
| `SELF_DECLARATION` | Il cliente attesta la proprietà senza una prova crittografica: è un'ultima risorsa, nei casi in cui la giurisdizione lo tollera. | Solo quando `allow_self_declaration` è `true` e la tua [`ownership_validation_mode`](https://docs.didit.me/it/transaction-monitoring/travel-rule#modalità-di-validazione-dell’assetto-proprietario) accetta una dichiarazione per il trasferimento collegato: mai in `FULL`, e in `SIMPLIFIED` solo sotto `simplified_validation_threshold`. Avviare una dichiarazione che la modalità non accetta restituisce `403`. |

### Contratto di verifica per la firma del messaggio

L'invio della firma restituisce `200` con `status: "VERIFIED"` quando dimostra di controllare il wallet.
Restituisce `400` e lascia la prova aperta, così il cliente può firmare di nuovo, con uno di questi valori di `code`:

| `code` | Significato |
| - | - |
| `SIGNATURE_INVALID` | La firma non dimostra il wallet: ha firmato un altro account o un'altra chiave, oppure il messaggio è diverso. Per un account a smart contract, il contratto ha risposto che la firma non è sua. |
| `SIGNATURE_UNSUPPORTED_SCHEME` | Il wallet ha firmato in un formato che Didit non verifica, ad esempio una multifirma Bitcoin o una firma completa BIP-322. |
| `SIGNATURE_LOOKUP_FAILED` | Il wallet potrebbe essere un account a smart contract e non è stato possibile controllare la sua chain in questo momento. La prova non viene mai verificata con questa risposta; firmare di nuovo la controlla di nuovo. |

### Contratto di verifica del test Satoshi

La verifica di un deposito del test Satoshi è asincrona, perché la transazione deve essere vista on-chain e poi confermata.
L'invio del `txid` del deposito restituisce `200` con `status: "PENDING"` finché il deposito non è ancora confermato on-chain - il `txid` viene conservato, non scartato.
Restituisce `200` con `status: "VERIFIED"` quando il deposito viene confermato.
Restituisce `400` con `status: "REJECTED"` per un deposito realmente errato: inviato da un altro wallet, con importo diverso da quello atteso verso l'indirizzo di deposito, più vecchio della challenge, oppure una transazione che ha già dimostrato un altro wallet. La prova viene chiusa e il cliente può avviarne una nuova finché la sessione ha tentativi disponibili.
Un deposito non ancora indicizzato restituisce anch'esso `200` con `status: "PENDING"`, e una ricerca non riuscita lato Didit restituisce `400` con codice `DEPOSIT_LOOKUP_FAILED`: in entrambi i casi la prova resta aperta e Didit continua a controllare.
Restituisce `410` se la finestra del test scade prima che venga rilevato un deposito valido.

Una volta inviato un `txid`, un job in background ricontrolla il deposito in attesa ogni cinque minuti e completa la prova dopo la conferma della transazione, quindi il cliente non deve inviare di nuovo il `txid`.
Quando passi un `satoshi_deposit_address`, il valore `expires_at` della sessione del widget viene esteso ad almeno la finestra di 24 ore del test Satoshi, così il deposito ha tempo di confermarsi prima che scada la sessione.

## Flusso

**1. Genera una sessione widget**

Chiama `POST /v3/travel-rule/widget-session/` con il wallet da verificare. Facoltativamente, collegalo a un trasferimento, così il trasferimento avanza automaticamente una volta dimostrata la proprietà.

**2. Apri l'URL restituito**

Indirizza il cliente all'`url` della risposta. Lì completa una prova: non servono un account Didit né una chiave API, perché il token nell'URL è l'autenticazione.

**3. Rileva il completamento**

Quando una prova viene verificata, il widget contrassegna la voce della rubrica degli indirizzi come verificata e, se la sessione è collegata a un trasferimento, lo fa avanzare. Osserva `travel_rule.status.updated` (per i trasferimenti collegati) oppure interroga il contesto del widget.

### Genera una sessione widget

Questo esempio collega la sessione al [trasferimento dichiarato verso un wallet in autocustodia](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#wallet-in-autocustodia-dichiarati) della guida Travel Rule, quindi `wallet_address` è il wallet di destinazione di quel trasferimento.
Una sessione collegata a un trasferimento accetta solo prove relative al wallet della controparte del trasferimento.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/widget-session/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9",
    "chain": "ETH",
    "holder_name": "Jane Doe",
    "vendor_data": "user-042",
    "transaction_id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
    "satoshi_deposit_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
    "callback_url": "https://yourapp.example/wallet-verified",
    "expires_in_minutes": 60
  }'
```

| Campo | Tipo | Descrizione |
| - | - | - |
| `wallet_address` | string | L'indirizzo da verificare. |
| `chain` | string | Identificatore della blockchain per l'indirizzo (ad esempio `ETH`, `BTC`, `SOL`). Usa lo stesso token che riportano i tuoi trasferimenti (`ETH`, non `ethereum`): il widget salva la voce della rubrica con questo `chain`, e un trasferimento su una catena diversa non corrisponde. La firma del messaggio richiede una catena riconosciuta da Didit. |
| `holder_name` | string | Nome del titolare del wallet, usato per il confronto con il nome del beneficiario. |
| `vendor_data` | string | Il tuo identificatore interno per il titolare, riportato sulla voce della rubrica creata. |
| `transaction_id` | string (uuid) | Facoltativo. UUID della transazione Didit di un trasferimento Travel Rule da far avanzare quando la prova viene verificata. Un UUID sconosciuto restituisce `404`, e una prova per un wallet diverso dal wallet della controparte del trasferimento viene rifiutata con `400`. Ometti il campo per verificare un wallet in modo autonomo. |
| `satoshi_deposit_address` | string | Facoltativo. Un indirizzo di deposito sotto il tuo controllo; fornirlo abilita il metodo `SATOSHI_TEST`. |
| `callback_url` | string | Facoltativo. URL a cui il widget reindirizza il cliente al termine. |
| `expires_in_minutes` | integer | Facoltativo. Durata del link generato, in minuti, da `5` a `10080` (predefinito `60`). Viene automaticamente portata ad almeno la finestra di test Satoshi di 24 ore quando passi un `satoshi_deposit_address`. |

```json theme={null}
{
  "widget_session_id": "77777777-8888-9999-aaaa-bbbbbbbbbbbb",
  "token": "3s9x...urlsafe",
  "url": "https://verify.didit.me/wallet-ownership/3s9x...urlsafe",
  "expires_at": "2026-07-07T13:00:00Z"
}
```

Apri sempre l'`url` restituito nella risposta così com'è: non costruirlo tu.

### Apri l'URL restituito

> [!WARNING]
>
> **Il widget in questa release funziona solo sul web. Apri l'`url` nel browser di sistema o in una scheda personalizzata, mai all'interno di una webview di un SDK mobile di Didit.**
>
> La firma dei messaggi funziona con i wallet installati nel browser del cliente, che il widget rileva tramite i protocolli EIP-6963 e Wallet Standard.
> L'associazione di un'app wallet mobile separata, ad esempio tramite codice QR, oggi non è disponibile, quindi il widget non passa a un'altra app.
> Una webview integrata nell'app, come la webview degli SDK Didit Web/Flutter/React Native/iOS/Android, **non può raggiungere i wallet del browser del cliente**, quindi un widget aperto lì lascia il cliente senza modo di firmare.
>
> Su mobile, avvia l'`url` con il browser del sistema operativo (`SFSafariViewController` / Chrome Custom Tabs, oppure il browser predefinito) invece di mostrarlo in una webview. Sul web, una scheda normale o un popup vanno bene.

### Rileva il completamento

Il widget espone un endpoint di lettura pubblico identificato dal token: interrogalo per vedere l'avanzamento, oppure affidati ai webhook quando la sessione è collegata a un trasferimento:

```bash theme={null}
curl https://verification.didit.me/v3/travel-rule/widget/{token}/
```

```json theme={null}
{
  "vasp_name": "Origin CASP SL",
  "wallet_address": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9",
  "chain": "ETH",
  "holder_name": "Jane Doe",
  "allowed_methods": ["MESSAGE_SIGNING", "SCREENSHOT", "SATOSHI_TEST", "SELF_DECLARATION"],
  "transfer_status": "UNCONFIRMED_OWNERSHIP",
  "callback_url": "https://yourapp.example/wallet-verified",
  "expires_at": "2026-07-07T13:00:00Z",
  "completed_at": null,
  "proofs": [
    {
      "proof_id": "88888888-9999-aaaa-bbbb-cccccccccccc",
      "method": "SATOSHI_TEST",
      "status": "PENDING",
      "wallet_address": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9",
      "chain": "ETH",
      "deposit_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
      "expected_amount": "0.000042817305521963",
      "expires_at": "2026-07-07T13:05:00.412731+00:00",
      "created_at": "2026-07-06T13:05:00.412731Z"
    }
  ],
  "customization": null
}
```

* `completed_at` diventa non nullo non appena una prova viene verificata.
* Ogni voce in `proofs` contiene i campi richiesti dal suo metodo: una prova `SATOSHI_TEST` aggiunge `deposit_address`, `expected_amount` e il proprio `expires_at`; una prova `MESSAGE_SIGNING` aggiunge `challenge`, la stringa che il cliente firma.
* Una prova `SATOSHI_TEST` può restare in `status: "PENDING"` mentre il suo deposito è visto on-chain ma non ancora confermato, senza alcuna azione richiesta né a te né al cliente: vedi [contratto di verifica del test Satoshi](#contratto-di-verifica-del-test-satoshi) sopra.
* Quando la sessione è stata generata con un `transaction_id`, la verifica della prova fa avanzare il trasferimento collegato e, su un'applicazione in produzione, parte il webhook [`travel_rule.status.updated`](https://docs.didit.me/it/integration/webhooks#tipi-di-evento).
  Preferisci il webhook al polling.
  Una richiesta `TRP` in entrata viene approvata e restituita al mittente, e passa a `COMPLETED` non appena l'approvazione viene consegnata. Qualsiasi altro trasferimento in `UNCONFIRMED_OWNERSHIP` (o un trasferimento in entrata `ON_HOLD`) passa a `COMPLETED`, oppure a `COUNTERPARTY_MISMATCHED_DATA` quando il nome del beneficiario non corrisponde al titolare del wallet. Un deposito sunrise regolato che si completa prosegue fino a `FINISHED`.
  Un trasferimento in uscita in `COUNTERPARTY_VASP_NOT_FOUND` passa a `COMPLETED`.
* Una prova `SCREENSHOT` resta in `status: "PENDING"` in questo contesto anche dopo che confermi la proprietà.
  La approvi con [`POST .../travel-rule/ownership/`](https://docs.didit.me/it/transaction-monitoring/travel-rule#conferma-dell’assetto-proprietario-del-wallet), che accetta solo un trasferimento in attesa di conferma della proprietà.
  Uno screenshot quindi non ha alcun percorso di approvazione su una sessione senza trasferimento collegato, oppure su una sessione collegata a un trasferimento in uscita in `COUNTERPARTY_VASP_NOT_FOUND`: disattiva `allow_screenshot_proof` se in quelle sessioni non deve essere offerto.
* Dopo una prova rifiutata, la sessione consente un nuovo tentativo finché restano tentativi. `max_attempts`, `attempts_used` e `attempts_remaining` riportano il conteggio, una prova rifiutata contiene `rejection_reason`, e quando `attempts_remaining` è `0` avviare un'altra prova restituisce `409` e devi generare una nuova sessione.
* L'endpoint del contesto restituisce `404` per un token sconosciuto e `410` quando la sessione è scaduta senza essere completata.

> [!NOTE]
>
> Qui non ci sono dipendenze una tantum: il widget e il tuo backend convergono sullo stesso stato durevole (la voce della rubrica verificata e lo stato del trasferimento). Quindi un webhook perso o una scheda chiusa si recuperano sempre rileggendo il trasferimento o il contesto del widget.

## Localizzazione e branding

Il widget viene visualizzato in **54 lingue**, in base alla lingua indicata nel link (oppure la lingua predefinita del browser).

Quando il White label è attivo per la tua applicazione, il widget eredita automaticamente il branding del flusso di verifica: logo, colori del brand, stile di pulsanti e pannelli, font personalizzato, favicon e il nome pubblico della tua app nel titolo.
Non serve alcuna configurazione aggiuntiva: si applica la stessa personalizzazione che hai impostato per le sessioni KYC.

Un utente che torna a un link già completato vede di nuovo la schermata di completamento; se hai passato un `callback_url`, il widget lo riporta lì.
I link scaduti mostrano una schermata di scadenza con il tuo brand, che invita l'utente a richiederne uno nuovo.
Crea una nuova sessione per l'utente con `POST /v3/travel-rule/widget-session/`: reinviare un trasferimento con `action: "resend"` non ne crea una.

## Prossimi passi

> [card] [Travel Rule](https://docs.didit.me/it/transaction-monitoring/travel-rule.md)
>
> Il ciclo di vita completo dello scambio, i canali, le impostazioni e i flussi di ricezione.

> [card] [Rubrica degli indirizzi wallet](https://docs.didit.me/it/transaction-monitoring/travel-rule.md#rubrica-degli-indirizzi-wallet)
>
> Registra i wallet che controlli, così i trasferimenti in entrata vengono associati a questi wallet.

> [card] [Webhook](https://docs.didit.me/it/integration/webhooks.md)
>
> Iscriviti a travel\_rule.status.updated per reagire quando una prova fa avanzare un trasferimento.

> [card] [SDK nativi](https://docs.didit.me/it/integration/native-sdks/overview.md)
>
> Apri l'URL del widget con il browser di sistema, non con la webview dell'SDK.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.