---
title: Allowlists
description: Control which addresses can receive your token by maintaining an approved list.
steps:
  - Enable the allowlist
  - Add an address
  - Review the list
  - Remove an address
---

Tokens created with `requiresAllowlist: true` enforce a list of approved destination addresses on allowlist-aware issuance flows such as minting and administrative transfers. Required for `tokenized-security` tokens. Payment transfers use wallet-level destination allowlists instead.

## Prerequisites

- A token created with `requiresAllowlist` enabled
- `tokens:write` permission on the API key

## How it works

<HowItWorks>

<Step number={1} title="Enable the allowlist">

The allowlist is configured at token creation time. Decide before creating whether your token requires one — it cannot be changed after deployment.

<StepPanel>
<Tabs items={["UI", "API"]} groupId="how-it-works">
<Tab value="UI">

In the **Create token** flow, step 3 of 3, toggle **Allowlist** on.

For `tokenized-security` tokens, the allowlist toggle is pre-enabled and locked.

The Compliance tab on the token detail page shows the allowlist management interface, with an Address and Label field and a Control Lists sidebar tracking entry and frozen account counts.

![Operational settings form showing the Allowlist toggle during token creation](/images/tokens/token-create-settings.png)

</Tab>
<Tab value="API">

Set `requiresAllowlist: true` when creating the token:

```typescript
body: JSON.stringify({
  name: "Acme Security",
  symbol: "ACMES",
  decimals: 8,
  template: "tokenized-security",
  requiresAllowlist: true,
  isMintable: true,
  isFreezable: true,
}),
```

Once deployed, the allowlist is enforced automatically on issuance flows.

</Tab>
</Tabs>
</StepPanel>

</Step>

<Step number={2} title="Add an address">

Add a wallet address to the allowlist before minting to it or using it as an administrative transfer destination.

<StepPanel>
<Tabs items={["UI", "API"]} groupId="how-it-works">
<Tab value="UI">

Open the token detail page and go to the **Compliance** tab, then select **Allowlist**.

Enter the wallet address and an optional label, then click **Add allowlist entry**. The address is enforced on the next allowlist-checked operation.

![Compliance Allowlist tab with empty address and label fields, ready to add a new entry](/images/tokens/allowlist-empty.png)

After adding, the entry appears below the form with a **Remove entry** button.

![Allowlist entry added and visible in the list](/images/tokens/allowlist-entry-added.png)

</Tab>
<Tab value="API">

```bash
curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "address": "7xKXz...9fGh",
    "label": "Treasury wallet"
  }'
```

```typescript
const res = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ address: "7xKXz...9fGh", label: "Treasury wallet" }),
  }
);
// res.data.entry.id — save this to remove the entry later
```

</Tab>
</Tabs>
</StepPanel>

</Step>

<Step number={3} title="Review the list">

Check which addresses are currently approved. Useful before minting to a new destination or during a compliance audit.

<StepPanel>
<Tabs items={["UI", "API"]} groupId="how-it-works">
<Tab value="UI">

The **Allowlist** tab shows all approved addresses, their labels, and when they were added.

Use the search field to find a specific address by label or public key.

</Tab>
<Tab value="API">

```bash
curl "https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist?search=So1&label=Treasury" \
  -H "Authorization: Bearer sk_test_..."
```

```typescript
const { data, meta } = await res.json();
// meta: { total, page, pageSize, hasMore }
```

Query parameters:

- `page`, `pageSize` — pagination (`pageSize` max 500, default 50).
- `search` — contains-style match over the entry address **and** label. A blank value is treated as no filter.
- `label` — restrict to entries with this exact label.

Search and the label filter run server-side over the whole list, so results aren't limited to the current page.

To populate a label filter, fetch the distinct labels in use (the response also
includes `total`, the unfiltered entry count, for a summary display):

```bash
curl https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist/labels \
  -H "Authorization: Bearer sk_test_..."
```

```typescript
const { data } = await res.json();
// data: { labels: ["Market maker", "Treasury"], total: 42 }
```

</Tab>
</Tabs>
</StepPanel>

</Step>

<Step number={4} title="Remove an address">

Remove an address when a holder's compliance status changes. Existing token holdings are unaffected — only future allowlist-enforced flows are blocked.

<StepPanel>
<Tabs items={["UI", "API"]} groupId="how-it-works">
<Tab value="UI">

In the **Compliance → Allowlist** tab, click **Remove entry** next to the address. The entry is removed immediately and the Control Lists sidebar updates to 0 entries.

</Tab>
<Tab value="API">

```bash
curl -X DELETE \
  https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist/alw_abc123 \
  -H "Authorization: Bearer sk_test_..."
```

Use the `entry.id` returned when the address was added.

</Tab>
</Tabs>
</StepPanel>

</Step>

</HowItWorks>

## Typical workflow for a tokenized security

1. Create the token with `requiresAllowlist: true` and template `tokenized-security`
2. [Deploy the token](/docs/tokens/deploy-a-token)
3. Collect wallet addresses from KYC-verified investors
4. Add each verified address to the allowlist
5. [Mint tokens](/docs/tokens/mint-and-burn) to allowlisted addresses
6. Remove addresses when compliance status changes
