# Set Up Travel Rule Compliance

Source: https://developers.bitgo.com/docs/crypto-as-a-service-travel-rule

## 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](/docs/get-started-intro)
* [Set Up Organization](/docs/crypto-as-a-service-organization)
* [Set Up Child Enterprises](/docs/crypto-as-a-service-child-enterprises)
* [Complete KYC Verification](/docs/crypto-as-a-service-know-your-customer) or
  [Complete KYB Verification](/docs/crypto-as-a-service-know-your-business)
* [Create Go Accounts](/docs/crypto-as-a-service-go-accounts)
* [Create Policies](/docs/crypto-as-a-service-policies)

## Cookbook

Need just the steps? Expand the cookbook below to get started:

<Cookbook slug="caas-travel-rule" title="Travel Rule" />

## 1. Get VASP

Get the verified VASP associated with a destination address.

> Endpoint: [Get VASP suggestions](/reference/travelrulevaspssuggestions)]

```shell cURL
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"
```
```js JavaScript
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.
```json JSON
{
  "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](/reference/travelrulevaspslist)

```shell cURL
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"
```
```js JavaScript
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.

```json JSON
{
  "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](/reference/travelrulewhitelistpost)

<Tabs>
<Tab title="BitGo Wallet">
Use this when the destination is another Go Account or another BitGo wallet.

```shell cURL
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"
  }'
```
```js JavaScript
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',
  });
```

</Tab>
<Tab title="Verified VASP">

Use this when the destination address belongs to a wallet outside of BitGo and the VASP is already verified.

```shell cURL
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"
  }'
```
```js JavaScript
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',
  });
```

</Tab>
<Tab title="New VASP">

Use this when the destination address belongs to a wallet outside of BitGo but the VASP is not yet verified.

```shell cURL
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"
    }
  }'
```
```js JavaScript
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',
    },
  });
```

</Tab>
</Tabs>

#### Step Result

<Tabs>
<Tab title="BitGo Wallet">

BitGo returns the wallet policy rule ID as the `whitelistId`, along with a `status` that reflects whether policy approval is still pending.

```json JSON
{
  "whitelistId": "5f8d0a2e1c9b4d7a3e6f8b2c1d4e7a9f",
  "status": "pending_policy_approval"
}
```

</Tab>
<Tab title="Verified VASP">
For verified VASP, BitGo returns the whitelist record ID and an initial `status`.

```json JSON
{
  "whitelistId": "59cd72485007a239fb00282ed480da1f",
  "status": "pending_vasp"
}
```

</Tab>
<Tab title="New VASP">
BitGo reviews the new VASP. If approved, the VASP becomes `verified` on the BitGo platform.

```json JSON
{
  "whitelistId": "59cd72485007a239fb00282ed480da1f",
  "status": "pending_vasp"
}
```
</Tab>
</Tabs>

## 4. Track Whitelist Status

Whitelisting resolves asynchronously. You can [Create Webhooks](/docs/crypto-as-a-service-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](/reference/travelrulewhitelistaddressstatusget)

```shell cURL
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"
```
```js JavaScript
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.

```json JSON
{
  "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.

## See Also

* [Create Policies](/docs/crypto-as-a-service-policies)
* [Create Go Accounts](/docs/crypto-as-a-service-go-accounts)
* [Create Webhooks](/docs/crypto-as-a-service-webhooks)
