Skip to main content
This guide walks you through handling a Travel Rule requirement when creating a crypto withdrawal directly through the API — from detecting the requirement on a quote to submitting proof and creating the transaction.
Prefer a managed UI? See Travel Rule withdrawal via the Travel Rule Widget — it handles the proof collection form for you.

Prerequisites

Walkthrough

Detect the requirement

When a quote is returned, check the requirements 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.

List quote RFIs

Call List request for information with reference set to the quote ID to find the pending travel-rule RFI.

Resolve the Travel Rule RFI

The RFI’s proofOptions field lists which proof mechanisms can resolve it — only the mechanisms that actually apply to this withdrawal are present (a satoshiTest option only appears for networks where a microtransfer is a viable proof). See Proof types for what each mechanism means and when it’s used. For a type: "travel-rule" RFI on a withdrawal, proof is submitted as beneficiaryProof — you’re proving who the external receiver is. Submit it with Update request for information.

Self-declaration

Submit the attestation plus the compliance details described by proofOptions.selfDeclaration.schema:

Message signing

Have the user sign proofOptions.messageSigning.message with their wallet, then submit the signature:
Uphold verifies the signature and enriches the response with did and status:

Satoshi test

Nothing is submitted through this endpoint — resolution is deferred until Uphold detects and confirms the on-chain microtransfer to the address described in proofOptions.satoshiTest. Poll Get request for information to know when it clears. Once confirmed, the RFI resolves with a flat proof — unlike the other two types, it’s not wrapped in beneficiaryProof:
Use Get request for information to confirm the RFI’s status before proceeding. If it fails (status: "failed") or expires, resolve the Travel Rule requirement again.

Create the transaction

Once the RFI is resolved (status: "ok"), create the transaction using the quote ID. If the original quote expired while during the RFI process, create a new quote and proceed — no additional Travel Rule data needs to be passed, as the resolved RFI is tied to the destination address rather than a specific quote.
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. After the transaction is created, the counterparty VASP has a window to review the Travel Rule data. If the data is rejected, Uphold emits a core.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 quote to an external address for 30 XRP. Verify the following:
  1. The quote response includes "travel-rule" in the requirements array.
  2. List requests for information returns an RFI with type: travel-rule, status: pending, and a populated proofOptions.
  3. Update request for information with a valid proof returns 200 with status: "ok".
  4. Create transaction with the quoteId succeeds.
  5. A core.transaction.status-changed webhook is received with status: completed (or failed if the counterparty rejects the data).
For the equivalent deposit guide, see Travel Rule deposit via the REST API.