is_ownership_verified: true, which lets a linked Travel Rule transfer advance out of UNCONFIRMED_OWNERSHIP.
When Didit mints it for you
You rarely need to mint a session yourself. Whenauto_wallet_verification is on in your Travel Rule settings (the default), Didit auto-mints a widget session at transaction creation whenever a transfer needs end-user proof of wallet control:
- The transfer is in
UNCONFIRMED_OWNERSHIP- the counterparty wallet was declared self-hosted at submission, or an inbound transfer hit an unverified address-book entry. - The transfer is outbound and in
COUNTERPARTY_VASP_NOT_FOUNDorON_HOLD- no counterparty VASP could be reached, so ownership proof is the remaining path to completion.
action_required block (type: "wallet_ownership", with the url to open), and the SDKs launch it automatically on client-side submission.
Mint manually with POST /v3/travel-rule/widget-session/ when you want to pre-verify a wallet before any transfer exists, or when you have auto_wallet_verification turned off.
What it proves
The widget offers up to four proof methods. Which ones appear depends on how you minted the session and your Travel Rule settings:| Method | How it works | When it’s offered |
|---|---|---|
MESSAGE_SIGNING | The customer signs a Didit-issued challenge string with their wallet. Supports EVM, Solana, Bitcoin, and Tron wallets; Didit verifies the signature against the address, and signing with a different account than the one being verified is rejected with a clear switch-accounts prompt. Installed browser wallets are discovered through the EIP-6963 and Wallet Standard protocols, so every extension appears as its own signing option, and mobile wallets connect through WalletConnect. | Always, for supported chain families. |
SATOSHI_TEST | The customer sends a tiny on-chain amount from the wallet to a deposit address you control; Didit’s watcher confirms the sender, amount tolerance, and confirmation depth, then automatically completes the proof once the deposit confirms - see Satoshi test verify contract below. | Only when you pass a satoshi_deposit_address at mint time. |
SCREENSHOT | The customer uploads a screenshot of the wallet showing the address (JPEG/PNG/WebP, up to 10 MB). Unlike the other methods it never auto-verifies: your compliance team reviews it and confirms from the transaction’s Travel Rule tab in the console, or via POST .../travel-rule/ownership/. | Only when allow_screenshot_proof is true in your settings. |
SELF_DECLARATION | The customer attests ownership without cryptographic proof - a last resort where the jurisdiction tolerates it. | Only when allow_self_declaration is true in your settings. |
Satoshi test verify contract
Verifying a Satoshi test deposit is asynchronous, because the transaction has to be seen on-chain and then reach enough confirmations. Submitting the deposit’stxid returns 200 with status: "PENDING" the moment the deposit is seen on-chain but before it has enough confirmations - the txid is retained, not discarded.
It returns 200 with status: "VERIFIED" once the deposit confirms.
It returns 400 only for a genuinely wrong deposit: absent, sent from an unexpected address, or the wrong amount.
It returns 410 if the test window expires before a valid deposit is seen.
A background job automatically rechecks pending deposits and completes the proof the moment the transaction confirms, so the customer is never stranded after sending funds - they do not need to resubmit the txid.
When SATOSHI_TEST is offered, the widget session’s own expires_at is extended to cover the Satoshi test window, giving the deposit time to confirm before the session itself expires.
Flow
Mint a widget session
Call
POST /v3/travel-rule/widget-session/ with the wallet you need verified. Optionally link it to a transfer so the transfer advances automatically once ownership is proven.Open the returned URL
Send your customer to the
url from the response. They complete a proof there - no Didit account or API key needed; the token in the URL is the authentication.Mint a widget session
| Field | Type | Description |
|---|---|---|
wallet_address | string | The wallet address to verify. |
chain | string | Chain identifier for the address (for example ethereum, bitcoin, solana). |
holder_name | string | Name of the wallet holder, used for the beneficiary name match. |
vendor_data | string | Your internal identifier for the holder, carried onto the created address-book entry. |
transaction_id | string (uuid) | Optional. Didit transaction UUID of a Travel Rule transfer to advance when the proof verifies. Omit to verify a wallet standalone. |
satoshi_deposit_address | string | Optional. A deposit address you control; supplying it enables the SATOSHI_TEST method. |
callback_url | string | Optional. Where the widget returns the customer after completion. |
expires_in_minutes | integer | Optional. Lifetime of the minted link; automatically extended to cover the Satoshi test window when SATOSHI_TEST is offered. |
url returned in the response verbatim - do not construct it yourself.
Open the returned URL
Detect completion
The widget exposes a public read endpoint keyed by the token - poll it to see progress, or rely on webhooks when the session is linked to a transfer:completed_atbecomes non-null once a proof is verified.- Each entry in
proofscarries the fields its method needs: aSATOSHI_TESTproof addsdeposit_address,expected_amount, and its ownexpires_at; aMESSAGE_SIGNINGproof addschallenge, the string the customer signs. - A
SATOSHI_TESTproof can sit atstatus: "PENDING"while its deposit is seen on-chain but unconfirmed, with no action needed from you or the customer - see Satoshi test verify contract above. - When the session was minted with a
transaction_id, verifying the proof advances the linked transfer (out ofUNCONFIRMED_OWNERSHIP, or resolving an inboundTRPtransfer), and atravel_rule.status.updatedwebhook fires. Prefer the webhook over polling. - The context endpoint returns
404for an unknown token and410once the session has expired without completing.
There are no one-shot dependencies here: the widget and your backend both converge on the same durable state (the verified address-book entry and the transfer status), so a dropped webhook or a closed tab is always recoverable by re-reading the transfer or the widget context.
Localization and branding
The widget renders in 54 languages, following the language path of the link (or the browser default). When whitelabel is enabled for your application, the widget inherits your verification-flow branding automatically: logo, brand colors, button and panel styling, custom font, favicon, and your app’s public name in the title. No separate configuration - the same customization you set up for KYC sessions applies here. A user who returns to an already-completed link sees the completion screen again; if you passed acallback_url, the widget returns them there.
Expired links show a branded expiry screen prompting them to request a new link (mint a new session or use action: "resend" flows as appropriate).
Next steps
Travel Rule
The full exchange lifecycle, rails, settings, and receiving flows.
Wallet address book
Register the wallets you control so inbound transfers resolve against them.
Webhooks
Subscribe to travel_rule.status.updated to react when a proof advances a transfer.
Native SDKs
Open the widget URL with the system browser, not the SDK webview.