End users in the CDP SDK represent individual users of your application. Each end user can have their own accounts, authentication methods, and access tokens. This enables you to build applications where users have their own wallets managed by CDP.
Creating End Users
Create an end user with email authentication
Create an end user with an email as the authentication method:import { CdpClient } from "@coinbase/cdp-sdk";
const cdp = new CdpClient();
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{
type: "email",
email: "[email protected]"
}
]
});
console.log(`End user ID: ${endUser.id}`);
console.log(`Access token: ${endUser.accessToken}`);
from cdp import CdpClient
from cdp.openapi_client.models.authentication_method import (
AuthenticationMethod,
)
from cdp.openapi_client.models.email_authentication import (
EmailAuthentication,
)
async with CdpClient() as cdp:
end_user = await cdp.end_user.create_end_user(
authentication_methods=[
AuthenticationMethod(
EmailAuthentication(
type="email",
email="[email protected]"
)
)
]
)
print(f"End user ID: {end_user.id}")
print(f"Access token: {end_user.access_token}")
Create end user with an EVM account
Create an end user and automatically provision an EVM account:const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{
type: "email",
email: "[email protected]"
}
],
evmAccount: {
createSmartAccount: false // Set to true for smart account
}
});
console.log(`End user ID: ${endUser.id}`);
console.log(`EVM account: ${endUser.evmAccount?.address}`);
from cdp.openapi_client.models.create_end_user_request_evm_account import (
CreateEndUserRequestEvmAccount,
)
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 # Set to True for smart account
)
)
print(f"End user ID: {end_user.id}")
print(f"EVM account: {end_user.evm_account.address}")
Create end user with a smart account
Create an end user with an ERC-4337 smart account:const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{
type: "email",
email: "[email protected]"
}
],
evmAccount: {
createSmartAccount: true,
enableSpendPermissions: true // Optional: Enable spend permissions
}
});
console.log(`Smart account: ${endUser.evmAccount?.address}`);
console.log(
`Owner account: ${endUser.evmAccount?.smartAccount?.ownerAddress}`
);
end_user = await cdp.end_user.create_end_user(
authentication_methods=[
AuthenticationMethod(
EmailAuthentication(
type="email",
email="[email protected]"
)
)
],
evm_account=CreateEndUserRequestEvmAccount(
create_smart_account=True,
enable_spend_permissions=True # Optional
)
)
print(f"Smart account: {end_user.evm_account.address}")
print(
f"Owner account: "
f"{end_user.evm_account.smart_account.owner_address}"
)
Access Tokens
Each end user receives an access token for authentication:
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{ type: "email", email: "[email protected]" }
]
});
// Store this token securely and provide it to the end user
const accessToken = endUser.accessToken;
// Validate an access token
const validation = await cdp.endUser.validateAccessToken({
accessToken: accessToken
});
console.log(`Valid: ${validation.valid}`);
console.log(`End user ID: ${validation.endUserId}`);
end_user = await cdp.end_user.create_end_user(
authentication_methods=[
AuthenticationMethod(
EmailAuthentication(type="email", email="[email protected]")
)
]
)
# Store this token securely and provide it to the end user
access_token = end_user.access_token
# Validate an access token
validation = await cdp.end_user.validate_access_token(
access_token=access_token
)
print(f"Valid: {validation.valid}")
print(f"End user ID: {validation.end_user_id}")
Store access tokens securely. They provide full access to the end user’s accounts.
Retrieving End Users
Get by ID
const endUser = await cdp.endUser.getEndUser({
id: "user_abc123..."
});
console.log(`Email: ${endUser.authenticationMethods[0].email}`);
console.log(`Account: ${endUser.evmAccount?.address}`);
end_user = await cdp.end_user.get_end_user(id="user_abc123...")
print(f"Email: {end_user.authentication_methods[0].email}")
print(f"Account: {end_user.evm_account.address}")
List All End Users
const response = await cdp.endUser.listEndUsers({
pageSize: 50,
pageToken: "optional-token"
});
for (const user of response.endUsers) {
console.log(`${user.id}: ${user.authenticationMethods[0].email}`);
}
if (response.nextPageToken) {
console.log("More pages available");
}
response = await cdp.end_user.list_end_users(
page_size=50,
page_token="optional-token"
)
for user in response.end_users:
print(f"{user.id}: {user.authentication_methods[0].email}")
if response.next_page_token:
print("More pages available")
Adding Accounts to End Users
Add an EVM Account
const account = await cdp.endUser.addEndUserEvmAccount({
endUserId: endUser.id
});
console.log(`Added EVM account: ${account.address}`);
account = await cdp.end_user.add_end_user_evm_account(
end_user_id=end_user.id
)
print(f"Added EVM account: {account.address}")
Add a Smart Account
const smartAccount = await cdp.endUser.addEndUserEvmSmartAccount({
endUserId: endUser.id,
enableSpendPermissions: false
});
console.log(`Added smart account: ${smartAccount.address}`);
console.log(`Owner: ${smartAccount.ownerAddress}`);
smart_account = await cdp.end_user.add_end_user_evm_smart_account(
end_user_id=end_user.id,
enable_spend_permissions=False
)
print(f"Added smart account: {smart_account.address}")
print(f"Owner: {smart_account.owner_address}")
Add a Solana Account
const solanaAccount = await cdp.endUser.addEndUserSolanaAccount({
endUserId: endUser.id
});
console.log(`Added Solana account: ${solanaAccount.address}`);
solana_account = await cdp.end_user.add_end_user_solana_account(
end_user_id=end_user.id
)
print(f"Added Solana account: {solana_account.address}")
Importing End Users
Import an existing end user from another project:
const imported = await cdp.endUser.importEndUser({
id: "user_from_another_project",
authenticationMethods: [
{
type: "email",
email: "[email protected]"
}
]
});
console.log(`Imported end user: ${imported.id}`);
imported = await cdp.end_user.import_end_user(
id="user_from_another_project",
authentication_methods=[
AuthenticationMethod(
EmailAuthentication(
type="email",
email="[email protected]"
)
)
]
)
print(f"Imported end user: {imported.id}")
Complete End User Flow
Here’s a complete example of creating and managing an end user:
import { CdpClient } from "@coinbase/cdp-sdk";
const cdp = new CdpClient();
// Step 1: Create end user with smart account
console.log("Creating end user...");
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [
{
type: "email",
email: "[email protected]"
}
],
evmAccount: {
createSmartAccount: true,
enableSpendPermissions: true
}
});
console.log(`End user created: ${endUser.id}`);
console.log(`Access token: ${endUser.accessToken}`);
console.log(`Smart account: ${endUser.evmAccount?.address}`);
// Step 2: Validate the access token
const validation = await cdp.endUser.validateAccessToken({
accessToken: endUser.accessToken
});
if (!validation.valid) {
throw new Error("Invalid access token");
}
// Step 3: Add additional accounts
console.log("Adding Solana account...");
const solanaAccount = await cdp.endUser.addEndUserSolanaAccount({
endUserId: endUser.id
});
console.log(`Solana account: ${solanaAccount.address}`);
// Step 4: List all end users
const allUsers = await cdp.endUser.listEndUsers({ pageSize: 10 });
console.log(`Total users: ${allUsers.endUsers.length}`);
// Step 5: Retrieve the end user
const retrieved = await cdp.endUser.getEndUser({ id: endUser.id });
console.log(`Retrieved user: ${retrieved.id}`);
console.log(
`Authentication: ${retrieved.authenticationMethods[0].email}`
);
See the example file at:
/home/daytona/workspace/source/examples/python/end_user/create_end_user.py
Authentication Methods
Currently supported authentication methods:
Email Authentication
AuthenticationMethod(
EmailAuthentication(
type="email",
email="[email protected]"
)
)
The CDP SDK currently supports email and SMS authentication methods. Additional authentication providers can be integrated through your application’s authentication layer.
Security Best Practices
- Never expose access tokens: Store them securely server-side
- Validate tokens: Always validate access tokens before operations
- Use HTTPS: Only transmit access tokens over secure connections
- Rotate tokens: Implement token rotation for long-lived applications
- Limit scope: Create end users with minimal required permissions
Use Cases
Embedded Wallets
Create wallets for your users without them managing private keys:
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [{ type: "email", email: user.email }],
evmAccount: { createSmartAccount: true }
});
// Store endUser.accessToken in your database
// Associate with your user record
Gasless Applications
Use smart accounts with paymasters:
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [{ type: "email", email: user.email }],
evmAccount: {
createSmartAccount: true,
enableSpendPermissions: true
}
});
// Users can transact without holding ETH
Multi-Chain Support
Provide accounts on multiple blockchains:
// Create with EVM account
const endUser = await cdp.endUser.createEndUser({
authenticationMethods: [{ type: "email", email: user.email }],
evmAccount: { createSmartAccount: false }
});
// Add Solana account
await cdp.endUser.addEndUserSolanaAccount({ endUserId: endUser.id });
// User now has both EVM and Solana accounts
Troubleshooting
Invalid Access Token
Always validate tokens before use:
const validation = await cdp.endUser.validateAccessToken({
accessToken: token
});
if (!validation.valid) {
// Token is invalid or expired
// Request user to re-authenticate
}
End User Not Found
Ensure you’re using the correct end user ID:
try {
const endUser = await cdp.endUser.getEndUser({ id: userId });
} catch (error) {
console.log("End user not found");
}
Account Already Exists
End users can have multiple accounts. If an account already exists, you’ll get an appropriate error.
Next Steps