> This page is for Taurus PROTECT, version v3.52.
> For other versions, use one of these documentation indexes:
> - v3.58 (default): https://taurushq.ferndocs.com/protect-capital/v3.58/llms.txt
> - v3.56: https://taurushq.ferndocs.com/protect-capital/v3.56/llms.txt
> - v3.54: https://taurushq.ferndocs.com/protect-capital/v3.54/llms.txt
> - v3.52: https://taurushq.ferndocs.com/protect-capital/v3.52/llms.txt
> - v3.50: https://taurushq.ferndocs.com/protect-capital/v3.50/llms.txt
> - v3.48: https://taurushq.ferndocs.com/protect-capital/v3.48/llms.txt
> - v3.46: https://taurushq.ferndocs.com/protect-capital/v3.46/llms.txt
> - v3.44: https://taurushq.ferndocs.com/protect-capital/v3.44/llms.txt
> - v3.42: https://taurushq.ferndocs.com/protect-capital/v3.42/llms.txt
> - v3.40: https://taurushq.ferndocs.com/protect-capital/v3.40/llms.txt
> - v3.38: https://taurushq.ferndocs.com/protect-capital/v3.38/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://taurushq.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://taurushq.ferndocs.com/_mcp/server.

# Whitelisted Addresses (External Addresses)

Whitelisting ensures that only approved addresses and contracts can interact with the system. Each whitelisting request goes through 4-eyes approval, which means the complete workflow consists of a number of steps:

1. [Authenticate with Protect](/protect-capital/reference/hmac-based-authentication)
2. Create an address of contract whitelisting request
3. List pending requests for approval
4. Sign & approve outstanding whitelisting requests

In the following sections, we walk you through this step by step.

## Creating a whitelisted address or asset request

The `WhitelistedAddressCreator` role is required to create a whitelisting request of any kind.

For the complete documentation on working with addresses and contracts, please consult the respective sections in the API documentation page:

* [Create whitelisted contracts](/protect-capital/v3.52/reference/contract-whitelisting/create)
* [Create whitelisted addresses](/protect-capital/v3.52/reference/whitelisted-addresses/create)

An example request may be created using the example below. These samples assume you have already configured your Protect instance with the appropriate setup for HMAC authentication, and are running these queries against one of the [example proxy implementations](/protect-capital/reference/hmac-based-authentication#proxy-server-for-hmac-requests). Alternatively, you can acquire a [Bearer token](/protect-capital/v3.52/reference/bearer-authentication)  using a username and password.

**`cURL`**

```curl cURL
export BASEURL=https://localhost:9000
curl --location "$BASEURL/api/rest/v1/whitelists/addresses" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
  "blockchain": "ETH",
  "address": "0xb794f5ea0ba39494ce839613fffba74279579267",
  "label": "API-Documentation - Test 8"
}'
```

> **Tip**
>
> **Call Result**
>
> A successful response for the POST call to create a simple whitelisting request might look like this:

```json
{
    "result": {
        "id": "3711"
    }
}
```

In this example, Taurus-PROTECT has created a new whitelisting request with a unique ID of `3711`. Taurus-PROTECT responds with a JSON object containing the newly assigned request id.

In the next steps we are going to look at how to approve this request.

## Listing outstanding requests

Before approving the requests through the API, even if we already know their IDs, we must learn their **metadata hash**. This property isn't automatically returned by the API on successful creation of a request, and therefore we must enumerate the outstanding requests using a separate API call.

We will work with the following 2 endpoints:

* [List whitelisted address for approval](/protect-capital/v3.52/reference/whitelisted-addresses/list-for-approval)
* [List whitelisted contracts for approval](/protect-capital/v3.52/reference/contract-whitelisting/list-for-approval)

The response from these queries will be similar, and detail everything about the request that is necessary to verify and approve.

**`List of addresses to approve`**

```javascript List of addresses to approve
{
    "result": [
        {
            "id": "31391",
            "tenantId": "1",
            "signedAddress": {
                "payload": "CgRET0dFGiJEUkJiM1B1M1FSaEZFTmtRR1ZLNHYxWWVreWZUNDQzOEVzKhdPdXRzaWRlIGFkZHJlc3MgTGF1cmVudA=="
            },
            "metadata": {
                "hash": "c7123e130e11ade04dd2913f20f7b75ffb71bf63f2b3f5ca4401388a90ab796b",
                "payload": {
                    "address": "DRBb3Pu3QRhFENkQGVK4v1YekyfT4438Es",
                    "addressType": "individual",
                    "contractType": "",
                    "currency": "DOGE",
                    "customerId": "",
                    "exchangeAccountId": "",
                    "label": "Outside address Laurent",
                    "linkedInternalAddresses": [],
                    "memo": ""
                },
                "payloadAsString": "{\"currency\":\"DOGE\",\"addressType\":\"individual\",\"address\":\"DRBb3Pu3QRhFENkQGVK4v1YekyfT4438Es\",\"memo\":\"\",\"label\":\"Outside address Laurent\",\"customerId\":\"\",\"exchangeAccountId\":\"\",\"linkedInternalAddresses\":[],\"contractType\":\"\"}"
            },
            "action": "create",
            "trails": [
                {
                    "id": "48279",
                    "userId": "11",
                    "externalUserId": "team1@bank.com",
                    "action": "created",
                    "date": "2025-04-22T07:57:42.689266Z"
                }
            ],
            "rulesContainer": "...",
            "rule": ", approvals = ['team1': 1 sig]",
            "approvers": {
                "parallel": [
                    {
                        "sequential": [
                            {
                                "externalGroupID": "team1",
                                "minimumSignatures": 1
                            }
                        ]
                    },
                    {
                        "sequential": [
                            {
                                "externalGroupID": "Traded",
                                "minimumSignatures": 1
                            }
                        ]
                    }
                ]
            },
            "blockchain": "DOGE",
            "status": "APPROVING",
            "network": "mainnet"
        }
    ],
    "totalItems": "1"
}
```

**`List of contracts for approval`**

```javascript List of contracts for approval
{
    "result": [
        {
            "id": "800",
            "tenantId": "1",
            "signedContractAddress": {
                "payload": "CgNFVEgSBFRFU1QaBFRFU1QgBioqMHgxNWNkMTcwMDFmZWZkYjMyYzczN2I0YzVhNzU2ODY1MGRjNmE4ZjEw"
            },
            "metadata": {
                "hash": "fa401332179c30fa52ffd5c352be4fa1e12b3333db9541ef7bd44914b435603f",
                "payload": {
                    "blockchain": "ETH",
                    "contractAddress": "0x15cd17001fefdb32c737b4c5a7568650dc6a8f10",
                    "decimals": "6",
                    "name": "TEST",
                    "symbol": "TEST"
                },
                "payloadAsString": "{\"blockchain\":\"ETH\",\"name\":\"TEST\",\"symbol\":\"TEST\",\"decimals\":\"6\",\"contractAddress\":\"0x15cd17001fefdb32c737b4c5a7568650dc6a8f10\"}"
            },
            "action": "create",
            "trails": [
                {
                    "id": "1961",
                    "userId": "11",
                    "externalUserId": "team1@bank.com",
                    "action": "created",
                    "date": "2025-04-24T07:40:32.506113Z"
                }
            ],
            "rulesContainer": "...",
            "rule": ", approvals = ['team1': 1 sig|'team1': 1 sig, 'team2': 1 sig]",
            "approvers": {
                "parallel": [
                    {
                        "sequential": [
                            {
                                "externalGroupID": "team1",
                                "minimumSignatures": 1
                            }
                        ]
                    },
                    {
                        "sequential": [
                            {
                                "externalGroupID": "team1",
                                "minimumSignatures": 1
                            },
                            {
                                "externalGroupID": "team2",
                                "minimumSignatures": 1
                            }
                        ]
                    }
                ]
            },
            "status": "APPROVING",
            "blockchain": "ETH",
            "network": "mainnet"
        },
        {
            "id": "799",
            "tenantId": "1",
            "signedContractAddress": {
                "payload": "CgNTT0wSBkthbWlubxoES01OTyAGKitLTU5vM25Kc0JYZmNwSlRWaFpjWExXN1JtVHdUdDRHVkZFN3N1VUJvOXNTOglTT0xfVE9LRU4="
            },
            "metadata": {
                "hash": "b3f8e1b38b7a8871a34d8a5151f394d292e1bd5cbbaddf838d48981bbaf43211",
                "payload": {
                    "blockchain": "SOL",
                    "contractAddress": "KMNo3nJsBXfcpJTVhZcXLW7RmTwTt4GVFE7suUBo9sS",
                    "decimals": "6",
                    "kind": "SOL_TOKEN",
                    "name": "Kamino",
                    "symbol": "KMNO"
                },
                "payloadAsString": "{\"blockchain\":\"SOL\",\"name\":\"Kamino\",\"symbol\":\"KMNO\",\"decimals\":\"6\",\"contractAddress\":\"KMNo3nJsBXfcpJTVhZcXLW7RmTwTt4GVFE7suUBo9sS\",\"kind\":\"SOL_TOKEN\"}"
            },
            "action": "create",
            "trails": [
                {
                    "id": "1960",
                    "userId": "11",
                    "externalUserId": "team1@bank.com",
                    "action": "created",
                    "date": "2025-04-22T14:25:37.647573Z"
                }
            ],
            "rulesContainer": "...",
            "rule": ", approvals = ['team1': 1 sig]",
            "approvers": {
                "parallel": [
                    {
                        "sequential": [
                            {
                                "externalGroupID": "team1",
                                "minimumSignatures": 1
                            }
                        ]
                    }
                ]
            },
            "status": "APPROVING",
            "blockchain": "SOL",
            "network": "mainnet"
        }
    ],
    "totalItems": "2"
}
```

## Signing the request

Signing the request involves using the ECDSA-SHA256 signature scheme. Please refer to the [Signing for approval](/protect-capital/v3.52/reference/signing-for-approval) page in the documentation for a tutorial on producing a valid signature.

The signature looks something like this: `I0xWyXI3L33DMZAKvvKXnlWD3GGXWh0AuL5zHD12DGp2/pR2h2MbgiQZrNGB27s/iB938UgMK1xUhbm1fNx8nw==`. You will also need the list of IDs of the requests that you are approving.

## Approving through the API

> ☑️ Approvals require a different role from creation
>
> For submitting the approval, the `WhitelistedAddressApprover` role will be necessary.

To approve whitelisting requests, you will need to use 2 separate endpoints depending on whether you are looking to whitelist an asset (smart contract), or an address for transactions:

* [Approve a whitelisted address](/protect-capital/v3.52/reference/whitelisted-addresses/approve)
* [Approve a whitelisted contract](/protect-capital/v3.52/reference/contract-whitelisting/approve)

Approvals all use the same JSON schema for the `POST` request:

```
{
  "comment": "mandatory comment to describe the action",
  "ids": ["1234", "2345"],
  "signature": "I0xWyXI3L33DMZAKvvKXnlWD3GGXWh0AuL5zHD12DGp2/pR2h2MbgiQZrNGB27s/iB938UgMK1xUhbm1fNx8nw=="
}
```

At this point, all data should be available for creating the API call:

* Comment is a free-form field, and typically you will want to use some internal reference or verifiable information that corresponds to the approval
* We prepared the `ids` sorted list in the "Prepare the Payload" section above.
* The `signature` field is the Base64 encoded signature created in the previous section.

Congratulations! You have successfully approved some whitelisting requests in Taurus Protect!