> ## 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 de propriedade de carteira: prova de controlo

> Widget alojado da Didit para provar que um cliente controla uma carteira: assinatura de mensagens, teste Satoshi, captura ou autodeclaração.

O widget de propriedade da carteira é uma página alojada que comprova que um dos seus clientes controla um endereço de carteira cripto específico. Ao abrigo do TFR da UE, uma VASP tem de verificar a propriedade de uma carteira autocustodiada (unhosted) antes de libertar fundos para ela ou a partir dela acima do limiar sunrise. O widget é a forma como a Didit recolhe essa prova, sem que tenha de criar os fluxos de assinatura por si.

Uma prova verificada marca a [entrada do livro de endereços de carteiras](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#livro-de-endereços-de-carteiras) correspondente como `is_ownership_verified: true`, o que permite que uma [transferência Travel Rule](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md) associada avance a partir de `UNCONFIRMED_OWNERSHIP`.

## Quando a Didit o cria para si

Raramente precisa de criar uma sessão manualmente.
Quando `auto_wallet_verification` está ativado nas suas [definições da Travel Rule](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#configuração) (o valor predefinido), a Didit cria automaticamente uma sessão do widget na criação da transação sempre que uma transferência precisa de prova de controlo da carteira pelo utilizador final:

* A transferência está em `UNCONFIRMED_OWNERSHIP`, porque a carteira da contraparte foi [declarada autocustodiada](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#carteiras-autocustodiadas-declaradas) na submissão.
* A transferência é de saída e está em `COUNTERPARTY_VASP_NOT_FOUND`, porque não foi possível identificar nenhuma VASP da contraparte, pelo que a prova de propriedade é o único caminho restante para a conclusão.

A sessão criada automaticamente é devolvida no bloco `action_required` da transação (`type: "wallet_ownership"`, com o `url` a abrir), e os SDK iniciam-na automaticamente na [submissão do lado do cliente](https://docs.didit.me/pt/transaction-monitoring/sdk-transaction-submission.md#ações-necessárias-do-utilizador).
As transferências de entrada que a Didit cria para si (um registo sunrise, uma consulta `TRP` de entrada ou a perna de entrada do canal `INTERNAL`) nunca recebem uma sessão criada automaticamente, mesmo quando ficam em `UNCONFIRMED_OWNERSHIP`.
Crie a sessão manualmente com `POST /v3/travel-rule/widget-session/` quando quiser pré-verificar uma carteira antes de existir qualquer transferência, quando tiver `auto_wallet_verification` desativado ou para uma dessas transferências de entrada.

## O que comprova

O widget oferece até quatro métodos de prova. Os que aparecem dependem da forma como a sessão foi criada e das suas [definições da Travel Rule](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#configuração):

| Método | Como funciona | Quando é oferecido |
| - | - | - |
| `MESSAGE_SIGNING` | O cliente assina uma string de desafio emitida pela Didit com a respetiva carteira. Suporta carteiras EVM, Solana, Bitcoin e Tron (no caso do Bitcoin, endereços legacy, SegWit aninhado, SegWit nativo e Taproot). A Didit verifica a assinatura contra o endereço, e uma assinatura feita com uma conta diferente da que está a ser verificada é rejeitada com uma mensagem clara a pedir que mude de conta. Contas de contrato inteligente EVM (carteiras inteligentes ERC-4337) também assinam: a Didit pergunta ao próprio contrato da conta, na cadeia em que a carteira está declarada, se a assinatura é válida (ERC-1271). Para uma conta que ainda não está implementada, verifica a assinatura ERC-6492 devolvida pela carteira, sem implementar a conta nem enviar qualquer transação. As contas de contrato inteligente são verificadas em todas as cadeias EVM suportadas. Ver [Contrato de verificação de assinatura de mensagens](#contrato-de-verificação-de-assinatura-de-mensagens) abaixo. As carteiras instaladas no navegador do cliente são detetadas através dos protocolos EIP-6963 e Wallet Standard, pelo que cada extensão aparece como uma opção de assinatura própria. Emparelhar uma aplicação de carteira móvel separada, por exemplo através de código QR, não está disponível atualmente. | Sempre, para as famílias de cadeias suportadas. |
| `SATOSHI_TEST` | O cliente envia um montante on-chain muito pequeno da carteira para um endereço de depósito que você controla. O monitor da Didit verifica o remetente (no caso de uma conta de contrato inteligente EVM, a própria conta, também quando um bundler ERC-4337 submete a transação), o montante e se o depósito está confirmado on-chain. Depois completa automaticamente a prova assim que o depósito é confirmado - ver [Contrato de verificação do teste Satoshi](#contrato-de-verificação-do-teste-satoshi) abaixo. | Apenas quando fornece um `satoshi_deposit_address` no momento da criação e a cadeia é uma cadeia EVM, Bitcoin ou Solana, por isso nunca numa sessão criada automaticamente. |
| `SCREENSHOT` | O cliente carrega uma captura de ecrã da carteira que mostra o endereço (JPEG/PNG/WebP, até 10 MB). Ao contrário dos outros métodos, nunca é verificada automaticamente: a sua equipa de conformidade analisa-a na fila de revisão de capturas de ecrã ([`GET /v3/travel-rule/wallet-proofs/`](https://docs.didit.me/pt/management-api/travel-rule/list-wallet-proofs)) e aprova ou rejeita-a ([`POST .../decision/`](https://docs.didit.me/pt/management-api/travel-rule/decide-wallet-proof)). Em alternativa, confirma a transferência a partir do separador **Travel Rule** da transação na consola ou através de [`POST .../travel-rule/ownership/`](https://docs.didit.me/pt/management-api/travel-rule/confirm-ownership) (para uma transferência em `UNCONFIRMED_OWNERSHIP` ou uma transferência recebida retida). | Apenas quando `allow_screenshot_proof` é `true` nas suas definições. |
| `SELF_DECLARATION` | O cliente atesta a propriedade sem prova criptográfica - um último recurso, em jurisdições que o toleram. | Apenas quando `allow_self_declaration` é `true` e a sua [`ownership_validation_mode`](https://docs.didit.me/pt/transaction-monitoring/travel-rule#modos-de-validação-de-propriedade) aceita uma declaração para a transferência associada: nunca em `FULL`, e em `SIMPLIFIED` apenas abaixo de `simplified_validation_threshold`. Iniciar uma declaração que o modo não aceita devolve `403`. |

### Contrato de verificação de assinatura de mensagens

Submeter a assinatura devolve `200` com `status: "VERIFIED"` assim que prova o controlo da carteira.
Devolve `400` e deixa a prova aberta, para que o cliente possa assinar novamente, com um destes valores de `code`:

| `code` | Significado |
| - | - |
| `SIGNATURE_INVALID` | A assinatura não prova a carteira: outra conta ou chave assinou, ou a mensagem é diferente. Para uma conta de contrato inteligente, o contrato respondeu que a assinatura não é a sua. |
| `SIGNATURE_UNSUPPORTED_SCHEME` | A carteira assinou num formato que a Didit não verifica, por exemplo uma multiassinatura Bitcoin ou uma assinatura completa BIP-322. |
| `SIGNATURE_LOOKUP_FAILED` | A carteira pode ser uma conta de contrato inteligente, e a sua cadeia não pôde ser verificada neste momento. A prova nunca é verificada com esta resposta; assinar novamente volta a verificá-la. |

### Contrato de verificação do teste Satoshi

A verificação de um depósito de teste Satoshi é assíncrona, porque a transação tem de ser vista on-chain e depois confirmada.
Submeter o `txid` do depósito devolve `200` com `status: "PENDING"` enquanto o depósito ainda não estiver confirmado on-chain - o `txid` é retido, não descartado.
Devolve `200` com `status: "VERIFIED"` assim que o depósito é confirmado.
Devolve `400` com `status: "REJECTED"` para um depósito efetivamente errado: enviado de outra carteira, com um montante diferente do esperado para o endereço de depósito, anterior ao desafio, ou uma transação que já provou outra carteira. A prova fica fechada e o cliente pode iniciar uma nova enquanto a sessão tiver tentativas disponíveis.
Um depósito que ainda não está indexado também devolve `200` com `status: "PENDING"`, e uma consulta que falha do lado da Didit devolve `400` com o código `DEPOSIT_LOOKUP_FAILED`. Em ambos os casos a prova fica aberta e a Didit continua a verificar.
Devolve `410` se a janela de teste expirar antes de ser visto um depósito válido.

Depois de um `txid` ter sido submetido, uma tarefa em segundo plano volta a verificar o depósito pendente a cada cinco minutos e completa a prova depois de a transação ser confirmada. Assim, o cliente não precisa de submeter novamente o `txid`.
Quando fornece um `satoshi_deposit_address`, o `expires_at` da própria sessão do widget é prolongado para pelo menos a janela de teste Satoshi de 24 horas, dando tempo ao depósito para ser confirmado antes de a sessão expirar.

## Fluxo

**1. Criar uma sessão do widget**

Chame `POST /v3/travel-rule/widget-session/` com a carteira que precisa de ser verificada. Opcionalmente, associe-a a uma transferência para que esta avance automaticamente assim que a propriedade for comprovada.

**2. Abrir o URL devolvido**

Envie ao seu cliente o `url` da resposta. Ele conclui ali uma prova, sem necessidade de conta Didit nem de chave de API; o token no URL é a autenticação.

**3. Detetar a conclusão**

Quando uma prova é verificada, o widget marca a entrada do livro de endereços como verificada e, se a sessão estiver associada a uma transferência, avança-a. Fique atento a `travel_rule.status.updated` (transferências associadas) ou faça polling ao contexto do widget.

### Criar uma sessão do widget

Este exemplo associa a sessão à [transferência declarada com carteira autocustodiada](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#carteiras-autocustodiadas-declaradas) do guia da Travel Rule, pelo que `wallet_address` é a carteira de destino dessa transferência.
Uma sessão associada a uma transferência só aceita provas para a carteira da contraparte da transferência.

```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 | Descrição |
| - | - | - |
| `wallet_address` | string | O endereço da carteira a verificar. |
| `chain` | string | Identificador da cadeia para o endereço (por exemplo `ETH`, `BTC`, `SOL`). Use o mesmo identificador que as suas transferências usam (`ETH`, e não `ethereum`): o widget guarda a entrada do livro de endereços com este `chain`, e uma transferência numa cadeia diferente não lhe corresponde. A assinatura de mensagens exige uma cadeia reconhecida pela Didit. |
| `holder_name` | string | Nome do titular da carteira, usado para a correspondência do nome do beneficiário. |
| `vendor_data` | string | O seu identificador interno para o titular, transportado para a entrada criada no livro de endereços. |
| `transaction_id` | string (uuid) | Opcional. UUID da transação Didit de uma transferência da Travel Rule a avançar quando a prova for verificada; um UUID desconhecido devolve `404`, e uma prova para qualquer carteira que não seja a carteira da contraparte da transferência é rejeitada com `400`. Omita para verificar uma carteira de forma independente. |
| `satoshi_deposit_address` | string | Opcional. Um endereço de depósito que controla; ao fornecê-lo, ativa o método `SATOSHI_TEST`. |
| `callback_url` | string | Opcional. Para onde o widget devolve o cliente após a conclusão. |
| `expires_in_minutes` | integer | Opcional. Duração da ligação criada, em minutos, de `5` a `10080` (predefinido `60`); é aumentada automaticamente para pelo menos a janela de teste Satoshi de 24 horas quando passa um `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"
}
```

Abra sempre o `url` devolvido na resposta tal como vem - não o construa você mesmo.

### Abrir o URL devolvido

> [!WARNING]
>
> **O widget só está disponível na web nesta versão. Abra o `url` no navegador do sistema ou num separador personalizado - nunca dentro de uma webview de um SDK móvel da Didit.**
>
> A assinatura de mensagens funciona com carteiras instaladas no navegador do cliente, que o widget deteta através dos protocolos EIP-6963 e Wallet Standard.
> A associação a uma aplicação de carteira móvel separada, por exemplo por código QR, não está disponível atualmente, pelo que o widget não transfere o cliente para outra aplicação.
> Uma webview dentro da aplicação, como a webview do SDK Web/Flutter/React Native/iOS/Android da Didit, **não consegue aceder às carteiras do navegador do cliente**, pelo que um widget aberto aí deixa o cliente sem forma de assinar.
>
> Em dispositivos móveis, abra o `url` com o navegador do sistema operativo (`SFSafariViewController` / Chrome Custom Tabs, ou o navegador predefinido) em vez de o apresentar numa webview. Na web, um separador normal ou uma janela pop-up é adequado.

### Detetar a conclusão

O widget expõe um endpoint público de leitura identificado pelo token - faça polling para ver o progresso, ou confie nos webhooks quando a sessão estiver associada a uma transferência:

```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` passa a não ser nulo assim que uma prova é verificada.
* Cada entrada em `proofs` traz os campos de que o seu método necessita: uma prova `SATOSHI_TEST` acrescenta `deposit_address`, `expected_amount` e o seu próprio `expires_at`; uma prova `MESSAGE_SIGNING` acrescenta `challenge`, a cadeia de caracteres que o cliente assina.
* Uma prova `SATOSHI_TEST` pode ficar com `status: "PENDING"` enquanto o depósito é visto na blockchain mas ainda não está confirmado, sem qualquer ação necessária da sua parte nem da do cliente - veja o [contrato de verificação do teste Satoshi](#contrato-de-verificação-do-teste-satoshi) acima.
* Quando a sessão foi criada com um `transaction_id`, a verificação da prova avança a transferência associada e, numa aplicação em produção, dispara-se um webhook [`travel_rule.status.updated`](https://docs.didit.me/pt/integration/webhooks#tipos-de-eventos). Prefira o webhook ao polling. Um pedido `TRP` recebido é aprovado de volta ao remetente e passa a `COMPLETED` assim que essa aprovação for entregue. Qualquer outra transferência em `UNCONFIRMED_OWNERSHIP` (ou uma recebida em `ON_HOLD`) passa a `COMPLETED`, ou a `COUNTERPARTY_MISMATCHED_DATA` quando o nome do beneficiário não corresponde ao titular da carteira, e um depósito sunrise liquidado que seja concluído avança para `FINISHED`. Uma transferência enviada em `COUNTERPARTY_VASP_NOT_FOUND` passa a `COMPLETED`.
* Uma prova `SCREENSHOT` mantém `status: "PENDING"` neste contexto, mesmo depois de confirmar a propriedade. Aprova-a com [`POST .../travel-rule/ownership/`](https://docs.didit.me/pt/transaction-monitoring/travel-rule#confirmar-a-propriedade-da-carteira), que só aceita uma transferência a aguardar a confirmação de propriedade. Por isso, uma captura de ecrã não tem caminho de aprovação numa sessão sem transferência associada, nem numa sessão associada a uma transferência enviada em `COUNTERPARTY_VASP_NOT_FOUND`: desative `allow_screenshot_proof` se essas sessões não devem oferecê-la.
* Após uma prova rejeitada, a sessão aceita uma nova tentativa enquanto restarem tentativas. `max_attempts`, `attempts_used` e `attempts_remaining` indicam a contagem, uma prova rejeitada inclui `rejection_reason`, e quando `attempts_remaining` for `0`, iniciar outra prova responde com `409` e tem de criar uma nova sessão.
* O endpoint de contexto devolve `404` para um token desconhecido e `410` quando a sessão expirou sem ter sido concluída.

> [!NOTE]
>
> Não há dependências de uso único aqui: o widget e o seu backend convergem para o mesmo estado durável (a entrada verificada do livro de endereços e o estado da transferência), pelo que um webhook perdido ou um separador fechado é sempre recuperável ao reler a transferência ou o contexto do widget.

## Localização e marca

O widget é apresentado em **54 idiomas**, seguindo o caminho de idioma da ligação (ou o idioma predefinido do navegador).

Quando a marca branca está ativada para a sua aplicação, o widget herda automaticamente a personalização do seu fluxo de verificação: logótipo, cores da marca, estilo dos botões e do painel, tipo de letra personalizado, favicon e o nome público da sua aplicação no título.
Não é necessária nenhuma configuração adicional: aplica-se a mesma personalização que configurou para as sessões de KYC.

Um utilizador que volta a uma ligação já concluída volta a ver o ecrã de conclusão; se tiver passado um `callback_url`, o widget reencaminha-o para esse endereço.
As ligações expiradas mostram um ecrã de expiração com a marca, que convida a pedir uma nova ligação.
Crie uma nova sessão para essa pessoa com `POST /v3/travel-rule/widget-session/`: reenviar uma transferência com `action: "resend"` não cria uma sessão.

## Próximos passos

> [card] [Travel Rule](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md)
>
> O ciclo de vida completo do intercâmbio, os canais, as definições e os fluxos de receção.

> [card] [Livro de endereços de carteiras](https://docs.didit.me/pt/transaction-monitoring/travel-rule.md#livro-de-endereços-de-carteiras)
>
> Registe as carteiras que controla para que as transferências recebidas sejam associadas a elas.

> [card] [Webhooks](https://docs.didit.me/pt/integration/webhooks.md)
>
> Subscreva travel\_rule.status.updated para reagir quando uma prova faz avançar uma transferência.

> [card] [SDKs nativos](https://docs.didit.me/pt/integration/native-sdks/overview.md)
>
> Abra o URL do widget com o navegador do sistema, e não com a webview do SDK.


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