Pre-generate embedded wallets for your users before they sign in, enabling you to fund accounts with assets upfront for a seamless first-time experience.
Supported authentication methods: Wallet pre-generation currently supports email, SMS, and Custom (JWT) authentication only. Support for additional authentication methods is coming soon.
Common mistake: A standard CDP API key alone is not enough for wallet pre-generation. You must also generate a Wallet Secret from the Server Wallet section of the CDP Portal.
Use the CDP SDK to create an end user with a specific authentication method. Once created, you can fund the wallet address before the user ever signs in.
The createEndUser method creates a new end user with an associated wallet. You specify the authentication method (email, SMS, or JWT) that the user will use to sign in later.
import { CdpClient } from "@coinbase/cdp-sdk";import "dotenv/config";const cdp = new CdpClient();try { // Create an end user with an email authentication method // and both EVM and Solana accounts. const endUser = await cdp.endUser.createEndUser({ authenticationMethods: [ { type: "email", email: "user@example.com" } ], evmAccount: { createSmartAccount: false }, solanaAccount: { createSmartAccount: false } }); console.log("Created end user:", endUser); // The end user's wallet addresses are now available. // You can fund these addresses before the user signs in. console.log("EVM address:", endUser.evmAccounts?.[0]); console.log("Solana address:", endUser.solanaAccounts?.[0]);} catch (error) { console.error("Error creating end user:", error);}
import asynciofrom cdp import CdpClientfrom cdp.openapi_client.models.authentication_method import AuthenticationMethodfrom cdp.openapi_client.models.create_end_user_request_evm_account import ( CreateEndUserRequestEvmAccount,)from cdp.openapi_client.models.create_end_user_request_solana_account import ( CreateEndUserRequestSolanaAccount,)from cdp.openapi_client.models.email_authentication import EmailAuthenticationfrom dotenv import load_dotenvload_dotenv()async def main(): async with CdpClient() as cdp: try: # Create an end user with an email authentication method # and both EVM and Solana accounts. end_user = await cdp.end_user.create_end_user( authentication_methods=[ AuthenticationMethod(EmailAuthentication(type="email", email="user@example.com")) ], evm_account=CreateEndUserRequestEvmAccount(create_smart_account=False), solana_account=CreateEndUserRequestSolanaAccount(create_smart_account=False), ) print("Created end user:", end_user) # The end user's wallet addresses are now available. # You can fund these addresses before the user signs in. except Exception as e: print(f"Error creating end user: {e}") raise easyncio.run(main())
import { CdpClient } from "@coinbase/cdp-sdk";import "dotenv/config";const cdp = new CdpClient();try { // Create an end user with an SMS authentication method // and both EVM and Solana accounts. const endUser = await cdp.endUser.createEndUser({ authenticationMethods: [ { type: "sms", phoneNumber: "+12055555555" } ], evmAccount: { createSmartAccount: false }, solanaAccount: { createSmartAccount: false } }); console.log("Created end user:", endUser); // The end user's wallet addresses are now available. // You can fund these addresses before the user signs in. console.log("EVM address:", endUser.evmAccounts?.[0]); console.log("Solana address:", endUser.solanaAccounts?.[0]);} catch (error) { console.error("Error creating end user:", error);}
import asynciofrom cdp import CdpClientfrom cdp.openapi_client.models.authentication_method import AuthenticationMethodfrom cdp.openapi_client.models.create_end_user_request_evm_account import ( CreateEndUserRequestEvmAccount,)from cdp.openapi_client.models.create_end_user_request_solana_account import ( CreateEndUserRequestSolanaAccount,)from cdp.openapi_client.models.sms_authentication import SmsAuthenticationfrom dotenv import load_dotenvload_dotenv()async def main(): async with CdpClient() as cdp: try: # Create an end user with an SMS authentication method # and both EVM and Solana accounts. end_user = await cdp.end_user.create_end_user( authentication_methods=[ AuthenticationMethod(SmsAuthentication(type="sms", phone_number="+12055555555")) ], evm_account=CreateEndUserRequestEvmAccount(create_smart_account=False), solana_account=CreateEndUserRequestSolanaAccount(create_smart_account=False), ) print("Created end user:", end_user) # The end user's wallet addresses are now available. # You can fund these addresses before the user signs in. except Exception as e: print(f"Error creating end user: {e}") raise easyncio.run(main())
import { CdpClient } from "@coinbase/cdp-sdk";import "dotenv/config";const cdp = new CdpClient();try { // Create an end user with a JWT authentication method // and both EVM and Solana accounts. const endUser = await cdp.endUser.createEndUser({ authenticationMethods: [ { type: "jwt", sub: "auth0|69387f18541e0e673845c6b6", kid: "1234567890" } ], evmAccount: { createSmartAccount: false }, solanaAccount: { createSmartAccount: false } }); console.log("Created end user:", endUser); // The end user's wallet addresses are now available. // You can fund these addresses before the user signs in. console.log("EVM address:", endUser.evmAccounts?.[0]); console.log("Solana address:", endUser.solanaAccounts?.[0]);} catch (error) { console.error("Error creating end user:", error);}
import asynciofrom cdp import CdpClientfrom cdp.openapi_client.models.authentication_method import AuthenticationMethodfrom cdp.openapi_client.models.create_end_user_request_evm_account import ( CreateEndUserRequestEvmAccount,)from cdp.openapi_client.models.create_end_user_request_solana_account import ( CreateEndUserRequestSolanaAccount,)from cdp.openapi_client.models.developer_jwt_authentication import DeveloperJWTAuthenticationfrom dotenv import load_dotenvload_dotenv()async def main(): async with CdpClient() as cdp: try: # Create an end user with a JWT authentication method # and both EVM and Solana accounts. end_user = await cdp.end_user.create_end_user( authentication_methods=[ AuthenticationMethod(DeveloperJWTAuthentication(type="jwt", sub="auth0|69387f18541e0e673845c6b6", kid="1234567890")) ], evm_account=CreateEndUserRequestEvmAccount(create_smart_account=False), solana_account=CreateEndUserRequestSolanaAccount(create_smart_account=False), ) print("Created end user:", end_user) # The end user's wallet addresses are now available. # You can fund these addresses before the user signs in. except Exception as e: print(f"Error creating end user: {e}") raise easyncio.run(main())
The sub value you use must match the sub claim in the JWTs your identity provider issues for this user.
If you already have access to your end users’ private keys, you can import them directly into Embedded Wallets. This is useful when migrating users from other wallet solutions—such as Server Wallets—to Embedded Wallets.
When to use import: Use this method when you have existing private keys for your users and want to preserve their wallet addresses during migration. The import flow is end-to-end encrypted, ensuring keys are never exposed outside of the SDK and the secure enclave.
The import API supports both EVM and Solana key types. Set keyType to either "evm" (hex-encoded private key) or "solana" (base58-encoded private key).
import { CdpClient } from "@coinbase/cdp-sdk";import "dotenv/config";const cdp = new CdpClient();try { // Import an end user with an existing private key. // For Solana: use keyType: "solana" with a base58-encoded private key. const endUser = await cdp.endUser.importEndUser({ authenticationMethods: [ { type: "jwt", sub: "auth0|69387f18541e0e673845c6b6", kid: "1234567890" } ], privateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", keyType: "evm", }); console.log("Imported end user:", endUser); console.log("EVM accounts:", endUser.evmAccountObjects);} catch (error) { console.error("Error importing end user:", error);}
import asynciofrom cdp import CdpClientfrom cdp.openapi_client.models.authentication_method import AuthenticationMethodfrom cdp.openapi_client.models.developer_jwt_authentication import DeveloperJWTAuthenticationfrom dotenv import load_dotenvload_dotenv()async def main(): async with CdpClient() as cdp: try: # Import an end user with an existing private key. # For Solana: use key_type="solana" with a base58-encoded private key. end_user = await cdp.end_user.import_end_user( authentication_methods=[ AuthenticationMethod(DeveloperJWTAuthentication(type="jwt", sub="auth0|69387f18541e0e673845c6b6", kid="1234567890")) ], private_key="0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", key_type="evm", ) print("Imported end user:", end_user) print("EVM accounts:", end_user.evm_account_objects) except Exception as e: print(f"Error importing end user: {e}") raise easyncio.run(main())
Security: Private keys should be handled with extreme care. Ensure you transmit keys securely and never log or expose them in your application. The import flow uses end-to-end encryption to protect keys during transmission.
By default, pre-generated wallets are created as EOA (Externally Owned Accounts). You can configure the account type and features using the evmAccount and solanaAccount parameters.
Smart accounts are only supported for EVM. Solana accounts must have createSmartAccount set to false.
Spend permissions allow you to grant allowances to specific addresses, enabling delegated transactions without requiring user signatures for each action. Learn more in the Spend Permissions documentation.
After creating an end user, you can add additional accounts directly on the EndUser object. Each end user can have up to 10 EVM EOA accounts, 10 EVM smart accounts, and 10 Solana accounts.