Skip to main content
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

1

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}`);
2

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}`);
3

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}`
);

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}`);
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}`);

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");
}

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}`);

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}`);

Add a Solana Account

const solanaAccount = await cdp.endUser.addEndUserSolanaAccount({
  endUserId: endUser.id
});

console.log(`Added Solana account: ${solanaAccount.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}`);

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}`
);

Authentication Methods

Currently supported authentication methods:

Email Authentication

{
  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

  1. Never expose access tokens: Store them securely server-side
  2. Validate tokens: Always validate access tokens before operations
  3. Use HTTPS: Only transmit access tokens over secure connections
  4. Rotate tokens: Implement token rotation for long-lived applications
  5. 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

Build docs developers (and LLMs) love