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

# Create a Wallet

MoonKey enables you to create embedded wallets for your users programmatically. These self-custodial wallets are owned by the authenticated user and secured using distributed key sharding.

You can create wallets either automatically when users authenticate, or manually when needed using the SDK.

<Tip>
  MoonKey supports automatically creating embedded wallets for your users when they log in to your app. View the [automatic wallet creation guide](/get-started/frontend-sdks/react/advance/automatic-wallet-creation) to learn more.
</Tip>

## React SDK

<Tabs>
  <Tab title="Ethereum">
    To create an Ethereum wallet with the React SDK, use the `createWallet` method from the `useCreateWallet` hook:

    ### Usage

    ```tsx theme={null}
    import { useCreateWallet } from '@moon-key/react-auth/ethereum';

    function CreateWalletButton() {
      const { createWallet } = useCreateWallet();
      
      const handleCreate = async () => {
        try {
          const wallet = await createWallet();
          console.log('Wallet created:', wallet.address);
        } catch (error) {
          console.error('Failed to create wallet:', error);
        }
      };
      
      return <button onClick={handleCreate}>Create Wallet</button>;
    }
    ```

    ### Returns

    <ResponseField name="wallet" type="Promise<Wallet>">
      A `Promise` for the wallet object containing the created wallet's details.

      <Expandable title="Wallet properties">
        <ResponseField name="address" type="string">
          The wallet's Ethereum address (e.g., `0x1234...5678`)
        </ResponseField>

        <ResponseField name="chainType" type="string">
          The chain type, always `'ethereum'` for Ethereum wallets
        </ResponseField>

        <ResponseField name="walletClient" type="WalletClient">
          The wallet client instance for performing operations
        </ResponseField>
      </Expandable>
    </ResponseField>

    ### Callbacks

    You can optionally register `onSuccess` or `onError` callbacks on the `useCreateWallet` hook:

    ```tsx theme={null}
    import { useCreateWallet } from '@moon-key/react-auth/ethereum';

    const { createWallet } = useCreateWallet({
      onSuccess: (wallet) => {
        console.log('Wallet created successfully:', wallet.address);
        // Navigate to wallet setup or show success message
      },
      onError: (error) => {
        console.error('Failed to create wallet:', error);
        // Show error message to user
      }
    });
    ```

    <ParamField path="onSuccess" type="(wallet: Wallet) => void">
      Optional callback to run after a user successfully creates a wallet.
    </ParamField>

    <ParamField path="onError" type="(error: Error) => void">
      Optional callback to run if there is an error during wallet creation.
    </ParamField>

    ### Complete example

    ```tsx theme={null}
    'use client';
    import { useCreateWallet, useMoonKey } from '@moon-key/react-auth/ethereum';
    import { useState } from 'react';

    export default function WalletCreation() {
      const { user, isAuthenticated } = useMoonKey();
      const [isCreating, setIsCreating] = useState(false);
      
      const { createWallet } = useCreateWallet({
        onSuccess: (wallet) => {
          console.log('Wallet created:', wallet.address);
          alert(`Wallet created: ${wallet.address}`);
        },
        onError: (error) => {
          console.error('Error:', error);
          alert('Failed to create wallet');
        }
      });
      
      if (!isAuthenticated) {
        return <div>Please sign in first</div>;
      }
      
      if (user?.wallet) {
        return (
          <div>
            <p>You already have a wallet:</p>
            <p>{user.wallet.address}</p>
          </div>
        );
      }
      
      const handleCreate = async () => {
        setIsCreating(true);
        try {
          await createWallet();
        } finally {
          setIsCreating(false);
        }
      };
      
      return (
        <div>
          <h2>Create Your Wallet</h2>
          <p>Create a self-custodial Ethereum wallet</p>
          <button onClick={handleCreate} disabled={isCreating}>
            {isCreating ? 'Creating...' : 'Create Wallet'}
          </button>
        </div>
      );
    }
    ```
  </Tab>

  <Tab title="Solana">
    To create a Solana wallet with the React SDK, use the `createWallet` method from the `useCreateWallet` hook:

    ### Usage

    ```tsx theme={null}
    import { useCreateWallet } from '@moon-key/react-auth/solana';

    function CreateWalletButton() {
      const { createWallet } = useCreateWallet();
      
      const handleCreate = async () => {
        try {
          const wallet = await createWallet();
          console.log('Wallet created:', wallet.address);
        } catch (error) {
          console.error('Failed to create wallet:', error);
        }
      };
      
      return <button onClick={handleCreate}>Create Wallet</button>;
    }
    ```

    ### Returns

    <ResponseField name="wallet" type="Promise<Wallet>">
      A `Promise` for the wallet object containing the created wallet's details.

      <Expandable title="Wallet properties">
        <ResponseField name="address" type="string">
          The wallet's Solana address (base58 encoded)
        </ResponseField>

        <ResponseField name="chainType" type="string">
          The chain type, always `'solana'` for Solana wallets
        </ResponseField>

        <ResponseField name="publicKey" type="PublicKey">
          The wallet's public key as a Solana `PublicKey` instance
        </ResponseField>
      </Expandable>
    </ResponseField>

    ### Callbacks

    You can optionally register `onSuccess` or `onError` callbacks on the `useCreateWallet` hook:

    ```tsx theme={null}
    import { useCreateWallet } from '@moon-key/react-auth/solana';

    const { createWallet } = useCreateWallet({
      onSuccess: (wallet) => {
        console.log('Wallet created successfully:', wallet.address);
        // Navigate to wallet setup or show success message
      },
      onError: (error) => {
        console.error('Failed to create wallet:', error);
        // Show error message to user
      }
    });
    ```

    <ParamField path="onSuccess" type="(wallet: Wallet) => void">
      Optional callback to run after a user successfully creates a wallet.
    </ParamField>

    <ParamField path="onError" type="(error: Error) => void">
      Optional callback to run if there is an error during wallet creation.
    </ParamField>

    ### Complete example

    ```tsx theme={null}
    'use client';
    import { useMoonKey } from '@moon-key/react-auth';
    import { useCreateWallet } from '@moon-key/react-auth/solana';
    import { useState } from 'react';

    export default function WalletCreation() {
      const { user, isAuthenticated } = useMoonKey();
      const [isCreating, setIsCreating] = useState(false);
      
      const { createWallet } = useCreateWallet({
        onSuccess: (wallet) => {
          console.log('Wallet created:', wallet.address);
          alert(`Wallet created: ${wallet.address}`);
        },
        onError: (error) => {
          console.error('Error:', error);
          alert('Failed to create wallet');
        }
      });
      
      if (!isAuthenticated) {
        return <div>Please sign in first</div>;
      }
      
      if (user?.wallet) {
        return (
          <div>
            <p>You already have a wallet:</p>
            <p>{user.wallet.address}</p>
          </div>
        );
      }
      
      const handleCreate = async () => {
        setIsCreating(true);
        try {
          await createWallet();
        } finally {
          setIsCreating(false);
        }
      };
      
      return (
        <div>
          <h2>Create Your Wallet</h2>
          <p>Create a self-custodial Solana wallet</p>
          <button onClick={handleCreate} disabled={isCreating}>
            {isCreating ? 'Creating...' : 'Create Wallet'}
          </button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## REST API

To create a new wallet for a user via the REST API, make a `POST` request to:

```bash theme={null}
POST https://api.moonkey.fun/v1/wallets/create
```

<Info>
  You must specify the user ID as the owner of the wallet. You can obtain a user ID by first [creating a user](/api-reference/users/create-user) before creating the wallet.
</Info>

### Authentication

Include your Secret API Key in the `Authorization` header:

```bash theme={null}
Authorization: Bearer sk_test_YOUR_SECRET_KEY
```

### Request body

<ParamField path="wallet_type" type="'ethereum' | 'solana'" required>
  The type of wallet to create.

  * `'ethereum'` - Create an Ethereum/EVM wallet
  * `'solana'` - Create a Solana/SVM wallet
</ParamField>

<ParamField path="user_id" type="string" required>
  The ID of the user who will own this wallet (e.g., `user_2Cu2uVhYy0OVgRcO913OsqIVaPI`).
</ParamField>

### Response

<ResponseField name="id" type="string">
  Unique ID of the created wallet. This is the primary identifier for the wallet.
</ResponseField>

<ResponseField name="app_id" type="string">
  The ID of your MoonKey application.
</ResponseField>

<ResponseField name="user_id" type="string">
  The ID of the user who owns this wallet.
</ResponseField>

<ResponseField name="public_address" type="string">
  The wallet's public address (Ethereum address or Solana public key).
</ResponseField>

<ResponseField name="wallet_type" type="'ethereum' | 'solana'">
  The type of wallet created.
</ResponseField>

<ResponseField name="verified" type="boolean">
  Whether the wallet has been verified. Always `true` for newly created wallets.
</ResponseField>

<ResponseField name="is_default" type="boolean">
  Whether this is the user's default wallet for this chain type.
</ResponseField>

<ResponseField name="created_at" type="number">
  Unix timestamp (in seconds) when the wallet was created.
</ResponseField>

<ResponseField name="updated_at" type="number">
  Unix timestamp (in seconds) when the wallet was last updated.
</ResponseField>

### Example request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.moonkey.fun/v1/wallets/create \
    --header 'Authorization: Bearer sk_test_YOUR_SECRET_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "wallet_type": "ethereum",
      "user_id": "user_2Cu2uVhYy0OVgRcO913OsqIVaPI"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.moonkey.fun/v1/wallets/create', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      wallet_type: 'ethereum',
      user_id: 'user_2Cu2uVhYy0OVgRcO913OsqIVaPI'
    })
  });

  const wallet = await response.json();
  console.log('Wallet created:', wallet.public_address);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
    'https://api.moonkey.fun/v1/wallets/create',
    headers={
      'Authorization': 'Bearer sk_test_YOUR_SECRET_KEY',
      'Content-Type': 'application/json'
    },
    json={
      'wallet_type': 'ethereum',
      'user_id': 'user_2Cu2uVhYy0OVgRcO913OsqIVaPI'
    }
  )

  wallet = response.json()
  print(f"Wallet created: {wallet['public_address']}")
  ```
</CodeGroup>

### Example response

```json theme={null}
{
  "id": "wallet_2Cu2uYcbwY9kcAFe2zd0P0SHftK",
  "app_id": "app_24ydphdixx2ydhF0E5WUFUKWNqi",
  "user_id": "user_2Cu2uVhYy0OVgRcO913OsqIVaPI",
  "public_address": "0xf1347fd847f19c250b4c9678ecaa27b0f6ce8804",
  "wallet_type": "ethereum",
  "verified": true,
  "is_default": true,
  "is_read_only": false,
  "is_imported": false,
  "created_at": 1659638371,
  "updated_at": 1659638371
}
```

## Automatic vs manual wallet creation

MoonKey provides two approaches to wallet creation:

### Automatic creation

Configure MoonKey to automatically create wallets when users authenticate:

```tsx theme={null}
import { MoonKeyProvider } from '@moon-key/react-auth';

<MoonKeyProvider
  publishableKey="your_publishable_key"
  config={{
    embeddedWallets: {
      createOnLogin: 'always' // Create wallet automatically for all users
    }
  }}
>
  {children}
</MoonKeyProvider>
```

**Best for:**

* Apps where all users need wallets
* Gaming applications
* NFT marketplaces
* DeFi applications
* Simplest onboarding experience

Learn more about [automatic wallet creation](/get-started/frontend-sdks/react/advance/automatic-wallet-creation).

### Manual creation

Use the `useCreateWallet` hook to create wallets programmatically:

```tsx theme={null}
const { createWallet } = useCreateWallet();
await createWallet();
```

**Best for:**

* Apps with optional blockchain features
* Progressive onboarding flows
* Users who opt-in to web3 features
* When you want to delay wallet creation for UX reasons

## Checking if a user has a wallet

Before creating a wallet, check if the user already has one:

```tsx theme={null}
import { useMoonKey } from '@moon-key/react-auth';

function MyComponent() {
  const { user } = useMoonKey();
  
  if (user?.wallet) {
    // User already has a wallet
    console.log('Wallet address:', user.wallet.address);
  } else {
    // User doesn't have a wallet yet
    // Show create wallet button
  }
}
```

## Common use cases

### Onboarding flow with wallet creation

```tsx theme={null}
'use client';
import { useMoonKey } from '@moon-key/react-auth';
import { useCreateWallet } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

export default function OnboardingFlow() {
  const { user, isAuthenticated } = useMoonKey();
  const { createWallet } = useCreateWallet();
  const [step, setStep] = useState<'welcome' | 'creating' | 'complete'>('welcome');
  
  if (!isAuthenticated) {
    return <div>Please sign in to continue</div>;
  }
  
  if (user?.wallet) {
    return <div>You already have a wallet! {user.wallet.address}</div>;
  }
  
  const handleCreateWallet = async () => {
    setStep('creating');
    try {
      await createWallet();
      setStep('complete');
    } catch (error) {
      console.error('Failed to create wallet:', error);
      setStep('welcome');
    }
  };
  
  return (
    <div>
      {step === 'welcome' && (
        <div>
          <h2>Welcome to Our App!</h2>
          <p>Create your self-custodial wallet to get started</p>
          <button onClick={handleCreateWallet}>Create Wallet</button>
        </div>
      )}
      
      {step === 'creating' && (
        <div>
          <h2>Creating Your Wallet...</h2>
          <p>This will only take a moment</p>
        </div>
      )}
      
      {step === 'complete' && (
        <div>
          <h2>Wallet Created!</h2>
          <p>Your wallet address: {user?.wallet?.address}</p>
          <button onClick={() => window.location.href = '/dashboard'}>
            Continue to Dashboard
          </button>
        </div>
      )}
    </div>
  );
}
```

### Optional wallet creation

```tsx theme={null}
import { useMoonKey } from '@moon-key/react-auth';
import { useCreateWallet } from '@moon-key/react-auth/ethereum';

export default function OptionalWalletFeature() {
  const { user } = useMoonKey();
  const { createWallet } = useCreateWallet();
  
  if (user?.wallet) {
    return <BlockchainFeatures />;
  }
  
  return (
    <div>
      <h2>Unlock Blockchain Features</h2>
      <p>Create a wallet to access NFTs, tokens, and more</p>
      <button onClick={() => createWallet()}>
        Create Wallet
      </button>
      <button onClick={() => window.history.back()}>
        Maybe Later
      </button>
    </div>
  );
}
```

### Server-side wallet creation

```typescript theme={null}
// On your backend
async function createWalletForUser(userId: string) {
  const response = await fetch('https://api.moonkey.fun/v1/wallets/create', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.MOONKEY_SECRET_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      wallet_type: 'ethereum',
      user_id: userId
    })
  });
  
  if (!response.ok) {
    throw new Error('Failed to create wallet');
  }
  
  const wallet = await response.json();
  return wallet;
}

// Example usage in an API endpoint
app.post('/api/setup-wallet', async (req, res) => {
  const { userId } = req.body;
  
  try {
    const wallet = await createWalletForUser(userId);
    res.json({ success: true, wallet });
  } catch (error) {
    res.status(500).json({ error: 'Failed to create wallet' });
  }
});
```

## Best practices

<AccordionGroup>
  <Accordion title="Check for existing wallets">
    Always check if a user already has a wallet before attempting to create one:

    ```tsx theme={null}
    if (user?.wallet) {
      console.log('User already has a wallet');
      return;
    }
    await createWallet();
    ```
  </Accordion>

  <Accordion title="Handle errors gracefully">
    Provide clear feedback when wallet creation fails:

    ```tsx theme={null}
    try {
      await createWallet();
      toast.success('Wallet created successfully!');
    } catch (error) {
      toast.error('Failed to create wallet. Please try again.');
      console.error('Wallet creation error:', error);
    }
    ```
  </Accordion>

  <Accordion title="Show loading states">
    Display loading indicators during wallet creation:

    ```tsx theme={null}
    const [isCreating, setIsCreating] = useState(false);

    const handleCreate = async () => {
      setIsCreating(true);
      try {
        await createWallet();
      } finally {
        setIsCreating(false);
      }
    };
    ```
  </Accordion>

  <Accordion title="Educate users">
    Explain what a wallet is and why they're creating one:

    ```tsx theme={null}
    <div className="wallet-info">
      <h3>What is a wallet?</h3>
      <p>A wallet lets you own digital assets like NFTs and tokens.</p>
      <p>Your wallet is self-custodial - only you can access it.</p>
    </div>
    ```
  </Accordion>

  <Accordion title="Use callbacks for post-creation actions">
    Handle navigation or UI updates after successful wallet creation:

    ```tsx theme={null}
    const { createWallet } = useCreateWallet({
      onSuccess: (wallet) => {
        // Log analytics
        analytics.track('wallet_created', { address: wallet.address });
        
        // Navigate to next step
        router.push('/wallet/funded');
      }
    });
    ```
  </Accordion>

  <Accordion title="Secure your API keys">
    Never expose your Secret API Key in client-side code:

    ```typescript theme={null}
    // ❌ WRONG - Never do this
    const apiKey = 'sk_live_...';

    // ✅ CORRECT - Use environment variables on server
    const apiKey = process.env.MOONKEY_SECRET_KEY;
    ```
  </Accordion>
</AccordionGroup>

## Error handling

Common errors and how to handle them:

```tsx theme={null}
try {
  await createWallet();
} catch (error) {
  if (error.message.includes('already has a wallet')) {
    toast.info('You already have a wallet');
  } else if (error.message.includes('not authenticated')) {
    toast.error('Please sign in first');
  } else if (error.message.includes('network')) {
    toast.error('Network error. Please check your connection.');
  } else {
    toast.error('Failed to create wallet. Please try again.');
  }
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Automatic Wallet Creation" icon="sparkles" href="/get-started/frontend-sdks/react/advance/automatic-wallet-creation">
    Configure automatic wallet creation on login
  </Card>

  <Card title="Send Transactions" icon="paper-plane" href="/authentication/user-authentication/ui-components/send-transaction">
    Learn how to send transactions with the wallet
  </Card>

  <Card title="Sign Messages" icon="signature" href="/authentication/user-authentication/ui-components/sign-message">
    Sign messages for authentication
  </Card>

  <Card title="Export Private Key" icon="key" href="/authentication/user-authentication/ui-components/export-key">
    Allow users to export their private key
  </Card>
</CardGroup>
