Prerequisites
- The user has completed onboarding and has the required capabilities enabled.
Walkthrough
Detect the requirement
When a quote is returned, check therequirements array. If it contains travel-rule, the requirement must be resolved before the transaction can be created. If requirements is empty, proceed directly to creating the transaction.
Resolve the requirement
The Travel Rule Widget allows the user to resolve a travel rule requirement for a specific quote.Create a widget session
Create a session tied to the quote by calling Create session withflow: withdrawal-form and the data property containing the quoteId. Each session is single-use and bound to a specific quote.
Widget sessions expire after 2 minutes. If the session expires before the user opens the widget — or while they are mid-form — the widget emits an
error event. Create a new session and re-mount to let the user retry. If the quote has also expired, create a new quote first before creating a new session.Set up the widget
Initialize the widget using the session returned from the API and mount it into your application. The widget does not unmount itself — always callunmount() after handling any event.
Both examples above are for web applications — either creating the iframe yourself or letting the SDK do it. For native apps using a WebView, see Native apps with the SDK for the SDK’s native-bundling pattern, or Setup with JavaScript for the no-SDK approach that loads the session
url directly as the WebView’s top-level page.Handle complete event
Once the user finishes the form, the widget automatically resolves the RFI by calling Update request for information internally with the collected data.Calling Update request for information yourself is only needed if you’re not using the widget and are resolving the Travel Rule requirement directly — not part of this widget-based flow.
complete fires, unmount the widget and confirm the RFI is resolved before proceeding — whether it is immediately ok or still pending depends on the proof type used:
- Synchronous proofs (self-declaration, cryptographic signature) — the RFI is fully resolved as soon as
completefires. If the quote has expired, create a new quote and proceed directly to Create transaction. - Asynchronous proofs (micro-transfer, e.g. a small on-chain test transaction) —
completefiring does not mean the RFI is resolved yet; resolution depends on the micro-transfer settling on-chain and confirmed by Uphold. Wait for it to settle, then create a new quote before creating the transaction.
Handle cancellations
Thecancel event fires when the user closes the widget without completing the form. The quote is not affected — it remains valid until it expires, so a new widget session can be created for the same quote to let the user retry. See cancel event for the event reference.
Handle errors
Theerror event fires when an unrecoverable error occurs. See error event for the full error shape and available properties.
Transaction failures
Unlike a deposit hold, a withdrawal transaction is created right away, so failures surface after creation — either when the Travel Rule payload is rejected at creation time, or when the counterparty VASP later rejects the data.Transaction creation errors
A transaction with anunspecified-error can indicate a rejected Travel Rule payload. The transaction was not completed. Collect fresh data via the widget and retry — the original quoteId remains valid unless it has since expired, in which case create a new quote first.
Counterparty rejection
After the transaction is created, the counterparty VASP has a window to review the Travel Rule data. If the data is rejected, Uphold emits acore.transaction.status-changed webhook with status: failed and statusDetails.reason: travel-rule-verification-failed. Common causes are the transaction being created before the RFI was fully resolved, or the beneficiary VASP being unrecognized or invalid. Notify the user and ask them to retry with a different destination.
Testing
To trigger a Travel Rule requirement on a withdrawal, use a GB user account and create an XRP withdrawal to an external address for 30 XRP. Verify the following:- The quote response includes
"travel-rule"in therequirementsarray. - After creating a widget session, complete the form — verify via Get request for information that the RFI status is
ok. - Create a new quote with the same parameters and call Create transaction with the new
quoteId; the transaction is created successfully. - A
core.transaction.status-changedwebhook is received withstatus: completed(orfailedif the counterparty rejects the data). - The transaction status updates to
completedwithin a few minutes, assuming no other blockers.