Overview
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.
Why pre-generate wallets?
- Pre-load assets: Fund wallets with loyalty points, gas, or welcome NFTs before users sign in
- Zero-friction onboarding: Users see a ready-to-use wallet on first login instead of an empty account
- Targeted campaigns: Prepare wallets for specific users (by email, phone, or JWT) before launching marketing campaigns
Prerequisites
Before pre-generating wallets, ensure you have:
- CDP API Key - Create one in the CDP Portal → API Keys
- Wallet Secret - Generate one in the CDP Portal → Server Wallet → Accounts
- CDP SDK - Install the CDP SDK in your project
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.
Getting your credentials
Create a CDP API Key
- Go to the CDP Portal
- Navigate to API Keys in the left sidebar
- Click Create API Key and save both the Key ID and Key Secret
Generate a Wallet Secret
- In the CDP Portal, go to Server Wallet → Accounts
- Click Generate in the Wallet Secret section
- Save the secret securely - you won’t be able to view it again
Configure your environment
Add both credentials to your .env file:CDP_API_KEY_ID=your-api-key-id
CDP_API_KEY_SECRET=your-api-key-secret
CDP_WALLET_SECRET=your-wallet-secret
For more details, see the Authentication documentation and Wallet Secret documentation.
Usage
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.
Creating an end user
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.
Email authentication
import { CdpClient } from "@coinbase/cdp-sdk";
import "dotenv/config";
const cdp = new CdpClient();
try {
// Create an end user with an email authentication method and an EVM account.
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{ type: "email", email: "[email protected]" }
],
evmAccount: { createSmartAccount: false }
});
console.log("Created end user:", endUser);
// The end user's wallet address is now available.
// You can fund this address before the user signs in.
console.log("Wallet address:", endUser.evmAccounts?.[0]);
} catch (error) {
console.error("Error creating end user:", error);
}
import asyncio
from cdp import CdpClient
from cdp.openapi_client.models.authentication_method import AuthenticationMethod
from cdp.openapi_client.models.create_end_user_request_evm_account import (
CreateEndUserRequestEvmAccount,
)
from cdp.openapi_client.models.email_authentication import EmailAuthentication
from dotenv import load_dotenv
load_dotenv()
async def main():
async with CdpClient() as cdp:
try:
# Create an end user with an email authentication method and an EVM account.
end_user = await cdp.end_user.create_end_user(
authentication_methods=[
AuthenticationMethod(EmailAuthentication(type="email", email="[email protected]"))
],
evm_account=CreateEndUserRequestEvmAccount(create_smart_account=False),
)
print("Created end user:", end_user)
# The end user's wallet address is now available.
# You can fund this address before the user signs in.
except Exception as e:
print(f"Error creating end user: {e}")
raise e
asyncio.run(main())
SMS authentication
import { CdpClient } from "@coinbase/cdp-sdk";
import "dotenv/config";
const cdp = new CdpClient();
try {
// Create an end user with an SMS authentication method and an EVM account.
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{ type: "sms", phoneNumber: "+12055555555" }
],
evmAccount: { createSmartAccount: false }
});
console.log("Created end user:", endUser);
// The end user's wallet address is now available.
// You can fund this address before the user signs in.
console.log("Wallet address:", endUser.evmAccounts?.[0]);
} catch (error) {
console.error("Error creating end user:", error);
}
import asyncio
from cdp import CdpClient
from cdp.openapi_client.models.authentication_method import AuthenticationMethod
from cdp.openapi_client.models.create_end_user_request_evm_account import (
CreateEndUserRequestEvmAccount,
)
from cdp.openapi_client.models.sms_authentication import SmsAuthentication
from dotenv import load_dotenv
load_dotenv()
async def main():
async with CdpClient() as cdp:
try:
# Create an end user with an SMS authentication method and an EVM account.
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),
)
print("Created end user:", end_user)
# The end user's wallet address is now available.
# You can fund this address before the user signs in.
except Exception as e:
print(f"Error creating end user: {e}")
raise e
asyncio.run(main())
Custom (JWT) Authentication
import { CdpClient } from "@coinbase/cdp-sdk";
import "dotenv/config";
const cdp = new CdpClient();
try {
// Create an end user with a JWT authentication method and an EVM account.
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{ type: "jwt", sub: "auth0|69387f18541e0e673845c6b6", kid: "1234567890" }
],
evmAccount: { createSmartAccount: false }
});
console.log("Created end user:", endUser);
// The end user's wallet address is now available.
// You can fund this address before the user signs in.
console.log("Wallet address:", endUser.evmAccounts?.[0]);
} catch (error) {
console.error("Error creating end user:", error);
}
import asyncio
from cdp import CdpClient
from cdp.openapi_client.models.authentication_method import AuthenticationMethod
from cdp.openapi_client.models.create_end_user_request_evm_account import (
CreateEndUserRequestEvmAccount,
)
from cdp.openapi_client.models.developer_jwt_authentication import DeveloperJWTAuthentication
from dotenv import load_dotenv
load_dotenv()
async def main():
async with CdpClient() as cdp:
try:
# Create an end user with a JWT authentication method and an EVM account.
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),
)
print("Created end user:", end_user)
# The end user's wallet address is now available.
# You can fund this address before the user signs in.
except Exception as e:
print(f"Error creating end user: {e}")
raise e
asyncio.run(main())
The sub value you use must match the sub claim in the JWTs your identity provider issues for this user.
What to read next