> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Kraken Integration

> Transfer crypto from Kraken exchange accounts to external wallets

# Kraken Integration

The Dynamic SDK provides a seamless way to transfer cryptocurrency from users' Kraken exchange accounts to external wallets. This enables your users to fund their wallets directly from their Kraken holdings without leaving your application.

## Overview

The Kraken integration consists of three functions:

| Function                                                                                         | Purpose                                |
| ------------------------------------------------------------------------------------------------ | -------------------------------------- |
| [`getKrakenAccounts`](/javascript/reference/client/get-kraken-accounts)                          | Fetch account balances from Kraken     |
| [`getKrakenWhitelistedAddresses`](/javascript/reference/client/get-kraken-whitelisted-addresses) | Get addresses approved for withdrawals |
| [`createKrakenExchangeTransfer`](/javascript/reference/client/create-kraken-exchange-transfer)   | Transfer crypto to an external wallet  |

## Prerequisites

Before using the Kraken integration:

1. **Kraken Account Connection** - Users must connect their Kraken account through Dynamic's exchange connection flow
2. **Address Whitelisting** - If enabled on the user's Kraken account, destination addresses must be whitelisted in Kraken's security settings
3. **Sufficient Balance** - The Kraken account must have enough funds for the transfer

## Quick Start

Here's a minimal example showing the complete flow:

```javascript theme={"system"}
import {
  getKrakenAccounts,
  getKrakenWhitelistedAddresses,
  createKrakenExchangeTransfer,
} from '@dynamic-labs-sdk/client';

// 1. Get the user's Kraken accounts and balances
const accounts = await getKrakenAccounts();
console.log('Available accounts:', accounts);

// 2. Check whitelisted addresses
const { destinations, enforcesAddressWhitelist } =
  await getKrakenWhitelistedAddresses();

if (enforcesAddressWhitelist) {
  console.log('Whitelisted addresses:', destinations);
}

// 3. Create a transfer
const transfer = await createKrakenExchangeTransfer({
  accountId: accounts[0].id,
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f7ABCD',
  amount: 0.1,
  currency: 'ETH',
});

console.log('Transfer status:', transfer.status);
```

## Understanding the Data

### Account Structure

When you call `getKrakenAccounts()`, you receive an array of accounts, each containing multiple currency balances:

```javascript theme={"system"}
const accounts = await getKrakenAccounts();

// Example account structure:
// {
//   id: 'acc_abc123',
//   exchange: 'kraken',
//   name: 'Main Account',
//   type: 'spot',
//   balances: [
//     { currency: 'ETH', balance: 2.5, availableBalance: 2.5 },
//     { currency: 'BTC', balance: 0.15, availableBalance: 0.15 },
//     { currency: 'USDC', balance: 1500.00, availableBalance: 1500.00 }
//   ]
// }
```

### Whitelisted Addresses

Kraken users can enable address whitelisting as a security measure. When enabled, withdrawals can only go to pre-approved addresses:

```javascript theme={"system"}
const { destinations, enforcesAddressWhitelist } =
  await getKrakenWhitelistedAddresses();

if (enforcesAddressWhitelist) {
  // User must select from whitelisted addresses
  console.log('Available destinations:', destinations);
  // destinations: [
  //   { address: '0x742d35...', tokens: ['ETH', 'USDC'] },
  //   { address: '0x8ba1f1...', tokens: ['ETH'] }
  // ]
} else {
  // User can enter any address
  console.log('Any address can be used');
}
```

## Complete React Example

Here's a production-ready React component for Kraken transfers:

```javascript theme={"system"}
import { useState, useEffect } from 'react';
import {
  getKrakenAccounts,
  getKrakenWhitelistedAddresses,
  createKrakenExchangeTransfer,
} from '@dynamic-labs-sdk/client';

const KrakenTransfer = () => {
  // State
  const [accounts, setAccounts] = useState([]);
  const [whitelistData, setWhitelistData] = useState(null);
  const [selectedAccountId, setSelectedAccountId] = useState('');
  const [currency, setCurrency] = useState('');
  const [amount, setAmount] = useState('');
  const [destination, setDestination] = useState('');
  const [loading, setLoading] = useState(true);
  const [submitting, setSubmitting] = useState(false);
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);

  // Load accounts and whitelisted addresses on mount
  useEffect(() => {
    const loadData = async () => {
      try {
        const [accountsData, whitelistResponse] = await Promise.all([
          getKrakenAccounts(),
          getKrakenWhitelistedAddresses(),
        ]);
        setAccounts(accountsData);
        setWhitelistData(whitelistResponse);
      } catch (err) {
        setError('Failed to load Kraken data. Is your account connected?');
      } finally {
        setLoading(false);
      }
    };
    loadData();
  }, []);

  // Get selected account
  const selectedAccount = accounts.find(acc => acc.id === selectedAccountId);

  // Get selected balance for the currency
  const selectedBalance = selectedAccount?.balances.find(
    b => b.currency === currency
  );

  // Filter whitelisted addresses by currency
  const availableDestinations = whitelistData?.destinations.filter(
    dest => dest.tokens?.includes(currency)
  ) || [];

  // Reset currency when account changes
  useEffect(() => {
    if (selectedAccount?.balances.length > 0) {
      setCurrency(selectedAccount.balances[0].currency);
    }
  }, [selectedAccountId]);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setSubmitting(true);
    setError(null);

    try {
      const transfer = await createKrakenExchangeTransfer({
        accountId: selectedAccountId,
        to: destination,
        amount: parseFloat(amount),
        currency,
      });
      setResult(transfer);
    } catch (err) {
      setError(err.message || 'Transfer failed');
    } finally {
      setSubmitting(false);
    }
  };

  if (loading) return <div>Loading Kraken data...</div>;
  if (error && !accounts.length) return <div>Error: {error}</div>;
  if (accounts.length === 0) {
    return <div>No Kraken accounts found. Please connect your Kraken account.</div>;
  }

  if (result) {
    return (
      <div>
        <h3>Transfer Created</h3>
        <p>ID: {result.id}</p>
        <p>Status: {result.status}</p>
        <p>Amount: {result.amount} {result.currency}</p>
        <button onClick={() => setResult(null)}>Make Another Transfer</button>
      </div>
    );
  }

  return (
    <form onSubmit={handleSubmit}>
      {error && <div style={{ color: 'red' }}>{error}</div>}

      {/* Account Selection */}
      <div>
        <label>Kraken Account</label>
        <select
          value={selectedAccountId}
          onChange={e => setSelectedAccountId(e.target.value)}
          required
        >
          <option value="">Select an account</option>
          {accounts.map(account => (
            <option key={account.id} value={account.id}>
              {account.name || `Account ${account.id.slice(0, 8)}`}
              {' '}({account.balances.length} currencies)
            </option>
          ))}
        </select>
      </div>

      {selectedAccount && (
        <>
          {/* Currency Selection */}
          <div>
            <label>Currency</label>
            <select
              value={currency}
              onChange={e => setCurrency(e.target.value)}
              required
            >
              {selectedAccount.balances.map(balance => (
                <option key={balance.currency} value={balance.currency}>
                  {balance.currency} (Balance: {balance.balance})
                </option>
              ))}
            </select>
          </div>

          {/* Amount Input */}
          <div>
            <label>Amount</label>
            <input
              type="number"
              step="any"
              min="0"
              value={amount}
              onChange={e => setAmount(e.target.value)}
              placeholder="0.0"
              required
            />
            {selectedBalance && (
              <small>Available: {selectedBalance.availableBalance ?? selectedBalance.balance}</small>
            )}
          </div>

          {/* Destination Address */}
          <div>
            <label>Destination Address</label>
            {whitelistData?.enforcesAddressWhitelist && availableDestinations.length > 0 ? (
              <select
                value={destination}
                onChange={e => setDestination(e.target.value)}
                required
              >
                <option value="">Select a whitelisted address</option>
                {availableDestinations.map(dest => (
                  <option key={dest.address} value={dest.address}>
                    {dest.address}
                  </option>
                ))}
              </select>
            ) : (
              <input
                type="text"
                value={destination}
                onChange={e => setDestination(e.target.value)}
                placeholder="0x..."
                required
              />
            )}
            {whitelistData?.enforcesAddressWhitelist && availableDestinations.length === 0 && (
              <small style={{ color: 'orange' }}>
                No whitelisted addresses for {currency}. Add one in Kraken settings.
              </small>
            )}
          </div>
        </>
      )}

      <button type="submit" disabled={submitting || !selectedAccountId}>
        {submitting ? 'Processing...' : 'Transfer'}
      </button>
    </form>
  );
};

export default KrakenTransfer;
```

## Filtering Accounts by Chain

You can filter accounts to show only balances for specific blockchains:

```javascript theme={"system"}
// Get only EVM-compatible assets (ETH, USDC on Ethereum, etc.)
const evmAccounts = await getKrakenAccounts({ chainName: 'EVM' });

// Get only Solana assets
const solanaAccounts = await getKrakenAccounts({ chainName: 'SOL' });

// Filter by specific network ID (e.g., Ethereum mainnet)
const ethereumMainnet = await getKrakenAccounts({
  chainName: 'EVM',
  networkId: 1
});
```

## Transfer with Network Specification

When transferring tokens that exist on multiple networks (like USDC), specify the network:

```javascript theme={"system"}
const transfer = await createKrakenExchangeTransfer({
  accountId: 'acc_123',
  to: '0x742d35...',
  amount: 100,
  currency: 'USDC',
  networkObject: {
    chainName: 'EVM',
    networkId: '137', // Polygon
  },
  description: 'Transfer USDC to Polygon wallet',
});
```

## Using Idempotency Keys

Prevent duplicate transfers by providing an idempotency key:

```javascript theme={"system"}
import { v4 as uuidv4 } from 'uuid';

const transferId = uuidv4();

const transfer = await createKrakenExchangeTransfer({
  accountId: 'acc_123',
  to: '0x742d35...',
  amount: 0.5,
  currency: 'ETH',
  id: transferId, // Idempotency key
});

// If this request is retried with the same `id`,
// it will return the existing transfer instead of creating a duplicate
```

## MFA Support

If the user has MFA enabled on their Kraken account, you may need to pass an MFA code:

```javascript theme={"system"}
const transfer = await createKrakenExchangeTransfer({
  accountId: 'acc_123',
  to: '0x742d35...',
  amount: 1.0,
  currency: 'BTC',
  mfaCode: '123456', // User-provided MFA code
});
```

## Error Handling

Handle common error scenarios:

```javascript theme={"system"}
try {
  const transfer = await createKrakenExchangeTransfer({
    accountId: selectedAccountId,
    to: destination,
    amount: parseFloat(amount),
    currency,
  });
  console.log('Transfer successful:', transfer.id);
} catch (error) {
  if (error.message.includes('insufficient')) {
    alert('Insufficient balance for this transfer');
  } else if (error.message.includes('whitelist')) {
    alert('This address is not whitelisted. Add it in your Kraken settings.');
  } else if (error.message.includes('mfa')) {
    alert('MFA verification required');
  } else {
    alert('Transfer failed: ' + error.message);
  }
}
```

## Best Practices

1. **Always check balances first** - Use `getKrakenAccounts()` to verify the user has sufficient funds before showing the transfer UI

2. **Respect whitelisting** - If `enforcesAddressWhitelist` is true, only show whitelisted addresses as options

3. **Use idempotency keys** - For production applications, always include an `id` parameter to prevent duplicate transfers from network retries

4. **Validate amounts client-side** - Check that the transfer amount doesn't exceed the available balance before submitting

5. **Show transfer status** - Display the transfer status to users so they know their transfer is being processed

## Related Functions

* [`getKrakenAccounts`](/javascript/reference/client/get-kraken-accounts) - Retrieve account balances
* [`getKrakenWhitelistedAddresses`](/javascript/reference/client/get-kraken-whitelisted-addresses) - Get approved withdrawal addresses
* [`createKrakenExchangeTransfer`](/javascript/reference/client/create-kraken-exchange-transfer) - Execute a transfer
