Crypto-as-a-Service
Set Up Travel Rule Compliance
Overview
Before your end users can withdraw crypto from a Go Account to an external address, you must whitelist the destination. Whitelisting runs travel rule compliance checks and exchanges counterparty information with the receiving Virtual Asset Service Provider (VASP) on your behalf.
For withdrawals to another BitGo wallet, whitelisting works differently. BitGo skips the travel rule checks and authorizes the destination through your wallet policy.
Note
Travel rule obligations vary by jurisdiction and transfer amount. BitGo applies the relevant threshold automatically based on your enterprise configuration. Contact your customer success manager (CSM) or support@bitgo.com for details.
Prerequisites
- Get Started
- Set Up Organization
- Set Up Child Enterprises
- Complete KYC Verification or Complete KYB Verification
- Create Go Accounts
- Create Policies
Cookbook
Need just the steps? Expand the cookbook below to get started:
Travel RuleOpen Cookbook1. Get VASP
Get the verified VASP associated with a destination address.
Endpoint: Get VASP suggestions]
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export WALLET_ADDRESS="<DESTINATION_WALLET_ADDRESS>"
export COIN="<ASSET_ID>" # for example: btc, eth, sol
curl -X GET \
"https://app.bitgo.com/api/travel-rule/v1/vasps/suggestions?walletAddress=$WALLET_ADDRESS&enterpriseId=$ENTERPRISE_ID&coin=$COIN" \
-H "Authorization: Bearer $ACCESS_TOKEN"
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const enterpriseId = '<CHILD_ENTERPRISE_ID>';
const walletAddress = '<DESTINATION_WALLET_ADDRESS>';
const coin = '<ASSET_ID>';
const response = await superagent
.get('https://app.bitgo.com/api/travel-rule/v1/vasps/suggestions')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.query({ walletAddress, enterpriseId, coin });
Step Result
BitGo returns the suggested VASP for the destination address. If your VASP wasn't correctly identified, then see the following step.
{
"vaspId": "BFXUS2NXXX",
"name": "Bitfinex",
"internalVasp": false,
"proofQuality": "SIGNED",
"source": "TRUST_BULLETIN_BOARD"
}
2. Search the VASP Registry (Optional)
If BitGo didn't successfully identify your VASP in the prior step, you can search for it manually.
Endpoint: List VASP
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X GET \
"https://app.bitgo.com/api/travel-rule/v1/vasps?status=VERIFIED&limit=50" \
-H "Authorization: Bearer $ACCESS_TOKEN"
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const response = await superagent
.get('https://app.bitgo.com/api/travel-rule/v1/vasps')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.query({ status: 'VERIFIED', limit: 50 });
Step Result
You receive a list of all VASPs registered with BitGo. Identify the appropriate one and save the vaspId.
Note
If your VASP isn't listed here, you can submit it as a new VASP in the following step.
{
"vasps": [
{
"id": "68c9f3ab12dd4a1b9e02f33c45a67890",
"vaspId": "BFXUS2NXXX",
"name": "Bitfinex",
"domain": "bitfinex.com",
"status": "VERIFIED",
"source": "TRUST",
"jurisdiction": "USA",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2025-05-01T08:00:00.000Z"
}
]
}
3. Whitelist Address
Submit the destination address for compliance review. This step covers whitelisting:
- A BitGo address or Go Account.
- An address with verified VASP.
- An address that requires verifying a new VASP.
Endpoint: Whitelist address
Use this when the destination is another Go Account or another BitGo wallet.
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export WALLET_ID="<GO_ACCOUNT_WALLET_ID>"
export DESTINATION_WALLET_ID="<BITGO_DESTINATION_WALLET_ID>"
curl -X POST \
https://app.bitgo.com/api/travel-rule/v1/whitelist \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"enterpriseId": "'"$ENTERPRISE_ID"'",
"walletId": "'"$WALLET_ID"'",
"coin": "eth",
"address": "'"$DESTINATION_WALLET_ID"'",
"custodyType": "hosted",
"label": "Internal Go Account"
}'
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const enterpriseId = '<CHILD_ENTERPRISE_ID>';
const walletId = '<GO_ACCOUNT_WALLET_ID>';
const destinationWalletId = '<BITGO_DESTINATION_WALLET_ID>';
const response = await superagent
.post('https://app.bitgo.com/api/travel-rule/v1/whitelist')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.set('Content-Type', 'application/json')
.send({
enterpriseId,
walletId,
coin: 'eth',
address: destinationWalletId,
custodyType: 'hosted',
label: 'Internal Go Account',
});
Use this when the destination address belongs to a wallet outside of BitGo and the VASP is already verified.
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export WALLET_ID="<GO_ACCOUNT_WALLET_ID>"
curl -X POST \
https://app.bitgo.com/api/travel-rule/v1/whitelist \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"enterpriseId": "'"$ENTERPRISE_ID"'",
"walletId": "'"$WALLET_ID"'",
"coin": "eth",
"address": "0xAbCd1234...",
"custodyType": "hosted",
"vaspId": "BFXUS2NXXX",
"label": "My Bitfinex account"
}'
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const enterpriseId = '<CHILD_ENTERPRISE_ID>';
const walletId = '<GO_ACCOUNT_WALLET_ID>';
const response = await superagent
.post('https://app.bitgo.com/api/travel-rule/v1/whitelist')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.set('Content-Type', 'application/json')
.send({
enterpriseId,
walletId,
coin: 'eth',
address: '0xAbCd1234...',
custodyType: 'hosted',
vaspId: 'BFXUS2NXXX',
label: 'My Bitfinex account',
});
Use this when the destination address belongs to a wallet outside of BitGo but the VASP is not yet verified.
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export WALLET_ID="<GO_ACCOUNT_WALLET_ID>"
curl -X POST \
https://app.bitgo.com/api/travel-rule/v1/whitelist \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"enterpriseId": "'"$ENTERPRISE_ID"'",
"walletId": "'"$WALLET_ID"'",
"coin": "eth",
"address": "0xDeFg5678...",
"custodyType": "hosted",
"label": "Exchange account",
"newVasp": {
"name": "NewExchange Inc.",
"domain": "newexchange.com"
}
}'
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const enterpriseId = '<CHILD_ENTERPRISE_ID>';
const walletId = '<GO_ACCOUNT_WALLET_ID>';
const response = await superagent
.post('https://app.bitgo.com/api/travel-rule/v1/whitelist')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.set('Content-Type', 'application/json')
.send({
enterpriseId,
walletId,
coin: 'eth',
address: '0xDeFg5678...',
custodyType: 'hosted',
label: 'Exchange account',
newVasp: {
name: 'NewExchange Inc.',
domain: 'newexchange.com',
},
});
Step Result
BitGo returns the wallet policy rule ID as the whitelistId, along with a status that reflects whether policy approval is still pending.
{
"whitelistId": "5f8d0a2e1c9b4d7a3e6f8b2c1d4e7a9f",
"status": "pending_policy_approval"
}
For verified VASP, BitGo returns the whitelist record ID and an initial status.
{
"whitelistId": "59cd72485007a239fb00282ed480da1f",
"status": "pending_vasp"
}
BitGo reviews the new VASP. If approved, the VASP becomes verified on the BitGo platform.
{
"whitelistId": "59cd72485007a239fb00282ed480da1f",
"status": "pending_vasp"
}
4. Track Whitelist Status
Whitelisting resolves asynchronously. You can Create Webhooks so BitGo notifies you when the status changes, or you can check the status manually by calling the API.
Endpoint: Get whitelist address status
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<CHILD_ENTERPRISE_ID>"
export WALLET_ID="<GO_ACCOUNT_WALLET_ID>"
export ADDRESS="<DESTINATION_WALLET_ADDRESS>"
curl -X GET \
"https://app.bitgo.com/api/travel-rule/v1/whitelist-address-status?address=$ADDRESS&walletId=$WALLET_ID&enterpriseId=$ENTERPRISE_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
import superagent from 'superagent';
const ACCESS_TOKEN = '<SERVICE_USER_ACCESS_TOKEN>';
const enterpriseId = '<CHILD_ENTERPRISE_ID>';
const walletId = '<GO_ACCOUNT_WALLET_ID>';
const address = '<DESTINATION_WALLET_ADDRESS>';
const response = await superagent
.get('https://app.bitgo.com/api/travel-rule/v1/whitelist-address-status')
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
.query({ address, walletId, enterpriseId });
Step Result
BitGo returns the current whitelist status for the address.
{
"whitelistResponse": [
{
"status": "VERIFIED",
"verifiedSource": "TRUST",
"address": "0xAbCd1234...",
"receiveAddress": "0xAbCd1234...",
"label": "My Bitfinex account",
"coin": "eth",
"walletId": "59cd72485007a239fb00282ed480da1f",
"updatedAt": "2025-06-01T12:00:00.000Z"
}
]
}
Next
Once your users' withdrawal addresses are whitelisted, they can send crypto through their Go Accounts.