---
title: Manage Allowlists
description: Control which addresses can hold your token using allowlists.
---

Tokens created with `requiresAllowlist: true` keep a list of approved destination addresses for controlled token actions. SDP enforces that list on allowlist-aware issuance flows such as minting and administrative transfers. Payment transfers use wallet-level destination allowlists instead of this token allowlist. This is essential for regulated tokens like tokenized securities.

When a token is created without an allowlist, the dashboard hides allowlist management for that token.

## Prerequisites

- A token with `requiresAllowlist` enabled
- The `tokens:write` permission for API key callers

For tokens with an on-chain allowlist configured, the mint endpoints also auto-add fresh destination wallets to the allowlist on first mint (both on-chain and in the DB mirror). Older allowlist tokens without an on-chain list enforce the DB allowlist only and reject destinations that aren't already added — use `POST /allowlist` first for those. If you want every entry to come through explicit operator review, use `POST /allowlist` ahead of mint and avoid handing out `tokens:write` to keys that should not be able to grow the allowlist. For those on-chain-list tokens, revoked entries are never auto-reactivated by mint — they return `403 DESTINATION_REVOKED` until re-added explicitly here. Legacy allowlist tokens without an on-chain list don't track a distinct revoked state — a removed destination simply fails with `403 NOT_ON_TOKEN_ALLOWLIST` until it's re-added.

## Add an address

<Tabs items={["curl", "TypeScript", "Java"]}>
<Tab value="curl">
```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"
  }'
```
</Tab>
<Tab value="TypeScript">
```typescript
const response = 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",
    }),
  }
);
```
</Tab>
<Tab value="Java">
```java
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "address": "7xKXz...9fGh",
          "label": "Treasury wallet"
        }"""))
    .build();
```
</Tab>
</Tabs>

The `label` field is optional but recommended for identifying entries.

## List entries

<Tabs items={["curl", "TypeScript", "Java"]}>
<Tab value="curl">
```bash
curl https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist \
  -H "Authorization: Bearer sk_test_..."
```
</Tab>
<Tab value="TypeScript">
```typescript
const response = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist",
  { headers: { "Authorization": "Bearer sk_test_..." } }
);
const { data, meta } = await response.json();
// meta: { total, page, pageSize, hasMore }
```
</Tab>
<Tab value="Java">
```java
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist"))
    .header("Authorization", "Bearer sk_test_...")
    .GET()
    .build();
```
</Tab>
</Tabs>

Supports `page` and `pageSize` query parameters for pagination (`pageSize` max 500), plus server-side filters:

- `search` — contains-style match over the entry address and label (blank means no filter).
- `label` — restrict to entries with this exact label.

Fetch the distinct labels in use with `GET /v1/issuance/tokens/{tokenId}/allowlist/labels`. Like every SDP response it's wrapped in `data`, so the payload is `{ data: { labels: string[]; total: number } }` (`total` is the unfiltered entry count) — useful for building a label filter and summary count.

## Remove an address

<Tabs items={["curl", "TypeScript", "Java"]}>
<Tab value="curl">
```bash
curl -X DELETE \
  https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist/alw_abc123 \
  -H "Authorization: Bearer sk_test_..."
```
</Tab>
<Tab value="TypeScript">
```typescript
await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist/alw_abc123",
  {
    method: "DELETE",
    headers: { "Authorization": "Bearer sk_test_..." },
  }
);
```
</Tab>
<Tab value="Java">
```java
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/allowlist/alw_abc123"))
    .header("Authorization", "Bearer sk_test_...")
    .DELETE()
    .build();
```
</Tab>
</Tabs>

## Workflow

A typical allowlist workflow for a tokenized security:

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