Freeze and Compliance

Freeze accounts, pause transfers, seize tokens, and screen addresses for compliance workflows.

SDP provides two public compliance workflows:

  • Token controls for assets that have isFreezable enabled or the pausable extension. These let you freeze individual accounts, pause all transfers globally, or seize tokens from a specific account.
  • Address screening through configured providers before you approve a destination, allowlist a wallet, or execute a regulated flow.

Token-control actions are available from the dashboard and the API. API key callers need tokens:admin for those onchain controls.

Screen an address

Use the Compliance API to check a Solana address across configured providers before onboarding a wallet or allowing a transfer destination.

curl -X POST https://api.solana.com/v1/compliance/address-screenings \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "address": "8dHEsGLpCZHZbXnFVvqWq4kMfM2pVDuNrXvVJVhQWRGZ",
    "network": "solana",
    "intent": "transfer_destination"
  }'
const response = await fetch(
  "https://api.solana.com/v1/compliance/address-screenings",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      address: "8dHEsGLpCZHZbXnFVvqWq4kMfM2pVDuNrXvVJVhQWRGZ",
      network: "solana",
      intent: "transfer_destination",
    }),
  }
);
const { data } = await response.json();
// data.screening.providers[] => { provider, status, riskScore, riskLevel, message, evaluatedAt }
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/compliance/address-screenings"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "address": "8dHEsGLpCZHZbXnFVvqWq4kMfM2pVDuNrXvVJVhQWRGZ",
          "network": "solana",
          "intent": "transfer_destination"
        }"""))
    .build();

The response aggregates provider-level results in data.screening.providers, including status, riskScore, riskLevel, and evaluatedAt. Use the Compliance API reference for the full schema.

Freeze an account

Prevent a specific holder from sending or receiving tokens:

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/freeze \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "accountAddress": "3xYZa...2aBc",
    "reason": "Suspicious activity investigation"
  }'
const response = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/freeze",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      accountAddress: "3xYZa...2aBc",
      reason: "Suspicious activity investigation",
    }),
  }
);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/freeze"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "accountAddress": "3xYZa...2aBc",
          "reason": "Suspicious activity investigation"
        }"""))
    .build();

The accountAddress can be the holder wallet address or the matching token account. SDP derives the associated token account when needed.

Unfreeze an account

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/unfreeze \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "accountAddress": "3xYZa...2aBc" }'
await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/unfreeze",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ accountAddress: "3xYZa...2aBc" }),
  }
);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/unfreeze"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        { "accountAddress": "3xYZa...2aBc" }"""))
    .build();

List frozen accounts

curl https://api.solana.com/v1/issuance/tokens/tok_abc123/frozen \
  -H "Authorization: Bearer sk_test_..."
const response = await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/frozen",
  { headers: { "Authorization": "Bearer sk_test_..." } }
);
const { data } = await response.json();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/frozen"))
    .header("Authorization", "Bearer sk_test_...")
    .GET()
    .build();

Pause token activity

Halt token activity globally. Requires the pausable extension:

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/pause \
  -H "Authorization: Bearer sk_test_..."
await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/pause",
  {
    method: "POST",
    headers: { "Authorization": "Bearer sk_test_..." },
  }
);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/pause"))
    .header("Authorization", "Bearer sk_test_...")
    .POST(HttpRequest.BodyPublishers.noBody())
    .build();

While paused, transfer-related and supply-management actions should be treated as unavailable until the token is unpaused.

Unpause

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/unpause \
  -H "Authorization: Bearer sk_test_..."
await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/unpause",
  {
    method: "POST",
    headers: { "Authorization": "Bearer sk_test_..." },
  }
);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/unpause"))
    .header("Authorization", "Bearer sk_test_...")
    .POST(HttpRequest.BodyPublishers.noBody())
    .build();

Seize tokens

Force-transfer tokens from one account to another without the holder's signature:

curl -X POST https://api.solana.com/v1/issuance/tokens/tok_abc123/seize \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: seize-001" \
  -d '{
    "seize": {
      "source": "3xYZa...2aBc",
      "destination": "9aBCd...4eEf",
      "amount": "1000000",
      "memo": "Court order #12345"
    }
  }'
await fetch(
  "https://api.solana.com/v1/issuance/tokens/tok_abc123/seize",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer sk_test_...",
      "Content-Type": "application/json",
      "Idempotency-Key": "seize-001",
    },
    body: JSON.stringify({
      seize: {
        source: "3xYZa...2aBc",
        destination: "9aBCd...4eEf",
        amount: "1000000",
        memo: "Court order #12345",
      },
    }),
  }
);
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/issuance/tokens/tok_abc123/seize"))
    .header("Authorization", "Bearer sk_test_...")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "seize-001")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {
          "seize": {
            "source": "3xYZa...2aBc",
            "destination": "9aBCd...4eEf",
            "amount": "1000000",
            "memo": "Court order #12345"
          }
        }"""))
    .build();

Seize also supports a /prepare endpoint for client-side signing.

Compliance workflow

  1. Detect suspicious activity
  2. Freeze the affected account
  3. Investigate the account and transactions
  4. Based on findings:
    • Unfreeze if cleared
    • Seize tokens to a recovery address
    • Force-burn tokens if required by regulation
  5. Log all actions with memos for audit trail