The official Java SDK for the Coinbase Developer Platform (CDP).
- Installation
- API Keys
- Usage
- End User Management
- HTTP Retry Configuration
- TokenProvider Pattern
- Low-Level API Access
- Authentication Tools
- Error Handling
- Development
- Documentation
- Support
- License
- Java 21 or higher
- Gradle 8.x (included via wrapper)
The SDK is also available via GitHub Packages. This requires GitHub authentication.
Step 1: Add your GitHub credentials to ~/.gradle/gradle.properties:
gpr.user=YOUR_GITHUB_USERNAME
gpr.token=YOUR_GITHUB_PERSONAL_ACCESS_TOKENGenerate a token at https://github.com/settings/tokens with
read:packagesscope.
Step 2: Add the repository and dependency in your build.gradle.kts:
repositories {
maven {
url = uri("https://maven.pkg.github.com/coinbase/cdp-sdk")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.token") as String? ?: System.getenv("GITHUB_TOKEN")
}
}
}
dependencies {
implementation("com.coinbase:cdp-sdk:0.6.0")
}To start, create a CDP API Key. Save the API Key ID and API Key Secret for use in the SDK. You will also need to create a wallet secret in the Portal to sign transactions.
Set your API keys as environment variables:
export CDP_API_KEY_ID="your-api-key-id"
export CDP_API_KEY_SECRET="your-api-key-secret"
export CDP_WALLET_SECRET="your-wallet-secret" # Required for write operationsThen initialize the client:
import com.coinbase.cdp.CdpClient;
try (CdpClient cdp = CdpClient.create()) {
var account = cdp.evm().createAccount(
new CreateEvmAccountRequest().name("my-account")
);
System.out.println("Created account: " + account.getAddress());
}import com.coinbase.cdp.CdpClient;
try (CdpClient cdp = CdpClient.builder()
.credentials("your-api-key-id", "your-api-key-secret")
.walletSecret("your-wallet-secret")
.build()) {
var account = cdp.evm().createAccount(
new CreateEvmAccountRequest().name("my-account")
);
}For more configuration options:
import com.coinbase.cdp.CdpClient;
import com.coinbase.cdp.CdpClientOptions;
CdpClientOptions options = CdpClientOptions.builder()
.apiKeyId("your-api-key-id")
.apiKeySecret("your-api-key-secret")
.walletSecret("your-wallet-secret")
.debugging(true) // Enable debug logging
.build();
try (CdpClient cdp = CdpClient.create(options)) {
// Use the client...
}The CDP client wraps an HTTP client and should be created once and reused throughout your application's lifecycle. Use try-with-resources to ensure proper cleanup:
try (CdpClient cdp = CdpClient.create()) {
// Use cdp throughout your application
}- Long-lived services: Create a single client instance at startup
- Serverless/request-based runtimes: Create once per cold start
- Concurrency: The client is safe to use across concurrent operations
import com.coinbase.cdp.openapi.model.CreateEvmAccountRequest;
var account = cdp.evm().createAccount(
new CreateEvmAccountRequest().name("my-evm-account")
);
System.out.println("Address: " + account.getAddress());import com.coinbase.cdp.openapi.model.CreateSolanaAccountRequest;
var account = cdp.solana().createAccount(
new CreateSolanaAccountRequest().name("my-solana-account")
);
System.out.println("Address: " + account.getAddress());// List EVM accounts
var evmAccounts = cdp.evm().listAccounts();
System.out.println("EVM accounts: " + evmAccounts.getAccounts().size());
// List Solana accounts
var solanaAccounts = cdp.solana().listAccounts();
System.out.println("Solana accounts: " + solanaAccounts.getAccounts().size());var account = cdp.evm().getAccount("0x1234...");
System.out.println("Account name: " + account.getName());Request testnet tokens for development:
import com.coinbase.cdp.openapi.model.RequestEvmFaucetRequest;
import com.coinbase.cdp.openapi.model.RequestEvmFaucetRequest.NetworkEnum;
import com.coinbase.cdp.openapi.model.RequestEvmFaucetRequest.TokenEnum;
var response = cdp.evm().requestFaucet(
new RequestEvmFaucetRequest()
.address(account.getAddress())
.network(NetworkEnum.BASE_SEPOLIA)
.token(TokenEnum.ETH)
);
System.out.println("Faucet tx: " + response.getTransactionHash());var response = cdp.evm().requestFaucet(
new RequestEvmFaucetRequest()
.address(account.getAddress())
.network(NetworkEnum.BASE_SEPOLIA)
.token(TokenEnum.USDC)
);import com.coinbase.cdp.openapi.model.SignEvmMessageRequest;
var response = cdp.evm().signMessage(
account.getAddress(),
new SignEvmMessageRequest().message("Hello, CDP!")
);
System.out.println("Signature: " + response.getSignature());import com.coinbase.cdp.openapi.model.EIP712Domain;
import com.coinbase.cdp.openapi.model.EIP712Message;
EIP712Domain domain = new EIP712Domain()
.name("MyDApp")
.version("1")
.chainId(1L)
.verifyingContract("0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC");
Map<String, Object> types = Map.of(
"Person", List.of(
Map.of("name", "name", "type", "string"),
Map.of("name", "wallet", "type", "address")
)
);
Map<String, Object> message = Map.of(
"name", "Alice",
"wallet", account.getAddress()
);
EIP712Message eip712Message = new EIP712Message()
.domain(domain)
.types(types)
.primaryType("Person")
.message(message);
var response = cdp.evm().signTypedData(account.getAddress(), eip712Message);
System.out.println("Signature: " + response.getSignature());import com.coinbase.cdp.client.evm.EvmClientOptions.TransferOptions;
import com.coinbase.cdp.openapi.model.SendEvmTransactionRequest.NetworkEnum;
import java.math.BigInteger;
var result = cdp.evm().transfer(
sender.getAddress(),
TransferOptions.builder()
.to(receiver.getAddress())
.amount(new BigInteger("10000")) // 0.01 USDC (6 decimals)
.token("usdc")
.network(NetworkEnum.BASE_SEPOLIA)
.build()
);
System.out.println("Transaction: " + result.getTransactionHash());
System.out.println("Explorer: https://sepolia.basescan.org/tx/" + result.getTransactionHash());import com.coinbase.cdp.client.solana.SolanaClientOptions.TransferOptions;
import com.coinbase.cdp.openapi.model.SendSolanaTransactionRequest.NetworkEnum;
import java.math.BigInteger;
var result = cdp.solana().transfer(
sender.getAddress(),
TransferOptions.builder()
.to(receiver.getAddress())
.amount(new BigInteger("10000000")) // 0.01 SOL (9 decimals)
.token("sol")
.network(NetworkEnum.SOLANA_DEVNET)
.build()
);
System.out.println("Signature: " + result.getSignature());The SDK provides an EndUserClient for creating, managing, and performing delegated signing/sending operations on behalf of end users.
import com.coinbase.cdp.openapi.model.CreateEndUserRequest;
var endUser = cdp.endUser().createEndUser(
new CreateEndUserRequest()
);
System.out.println("User ID: " + endUser.getUserId());import com.coinbase.cdp.client.enduser.EndUserClientOptions.ListEndUsersOptions;
var response = cdp.endUser().listEndUsers(
ListEndUsersOptions.builder()
.pageSize(10)
.build()
);
System.out.println("End users: " + response.getEndUsers().size());var endUser = cdp.endUser().getEndUser("user-id");
System.out.println("User: " + endUser.getUserId());// Add an EVM EOA account
var evmResult = cdp.endUser().addEndUserEvmAccount("user-id");
System.out.println("EVM address: " + evmResult.getEvmAccount().getAddress());
// Add an EVM smart account
import com.coinbase.cdp.openapi.model.AddEndUserEvmSmartAccountRequest;
var smartResult = cdp.endUser().addEndUserEvmSmartAccount(
"user-id",
new AddEndUserEvmSmartAccountRequest()
);
// Add a Solana account
var solResult = cdp.endUser().addEndUserSolanaAccount("user-id");
System.out.println("Solana address: " + solResult.getSolanaAccount().getAddress());import com.coinbase.cdp.openapi.model.SignEvmTransactionWithEndUserAccountRequest;
var result = cdp.endUser().signEvmTransaction(
"user-id",
new SignEvmTransactionWithEndUserAccountRequest()
.transaction("0x...")
.address("0x1234...")
);
System.out.println("Signature: " + result.getSignature());import com.coinbase.cdp.openapi.model.SignEvmMessageWithEndUserAccountRequest;
var result = cdp.endUser().signEvmMessage(
"user-id",
new SignEvmMessageWithEndUserAccountRequest()
.message("Hello, CDP!")
.address("0x1234...")
);
System.out.println("Signature: " + result.getSignature());import com.coinbase.cdp.openapi.model.SendEvmTransactionWithEndUserAccountRequest;
var result = cdp.endUser().sendEvmTransaction(
"user-id",
new SendEvmTransactionWithEndUserAccountRequest()
.transaction("0x...")
.address("0x1234...")
.network("base-sepolia")
);
System.out.println("Transaction hash: " + result.getTransactionHash());import com.coinbase.cdp.openapi.model.SendEvmAssetWithEndUserAccountRequest;
var result = cdp.endUser().sendEvmAsset(
"user-id",
"0x1234...", // sender address
"usdc", // asset
new SendEvmAssetWithEndUserAccountRequest()
.to("0x9F663335Cd6Ad02a37B633602E98866CF944124d")
.amount("10000")
.network("base-sepolia")
);
System.out.println("Transaction hash: " + result.getTransactionHash());import com.coinbase.cdp.openapi.model.SignSolanaMessageWithEndUserAccountRequest;
var result = cdp.endUser().signSolanaMessage(
"user-id",
new SignSolanaMessageWithEndUserAccountRequest()
.message("Hello, Solana!")
.address("7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV")
);
System.out.println("Signature: " + result.getSignature());import com.coinbase.cdp.openapi.model.SendSolanaAssetWithEndUserAccountRequest;
var result = cdp.endUser().sendSolanaAsset(
"user-id",
"7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV", // sender address
"usdc", // asset
new SendSolanaAssetWithEndUserAccountRequest()
.to("3KzDtddx4i53FBkvCzuDmRbaMozTZoJBb1TToWhz3JfE")
.amount("1000000")
.network("solana-devnet")
);
System.out.println("Signature: " + result.getTransactionSignature());Revoke all active delegations for an end user:
cdp.endUser().revokeDelegation("user-id");The SDK supports configurable HTTP retry behavior with exponential backoff and jitter for handling transient failures and rate limiting.
import com.coinbase.cdp.http.RetryConfig;
// Default: 3 retries, 100ms initial backoff, 30s max, 2x multiplier, 25% jitter
RetryConfig config = RetryConfig.defaultConfig();import com.coinbase.cdp.http.RetryConfig;
import java.time.Duration;
RetryConfig retryConfig = RetryConfig.builder()
.maxRetries(5)
.initialBackoff(Duration.ofMillis(200))
.maxBackoff(Duration.ofSeconds(60))
.backoffMultiplier(2.0)
.jitterFactor(0.3)
.build();
try (CdpClient cdp = CdpClient.builder()
.credentials("api-key-id", "api-key-secret")
.retryConfig(retryConfig)
.build()) {
// Requests will retry with custom backoff
}RetryConfig noRetries = RetryConfig.disabled();
CdpClientOptions options = CdpClientOptions.builder()
.apiKeyId("api-key-id")
.apiKeySecret("api-key-secret")
.retryConfig(noRetries)
.build();By default, the SDK retries on these status codes:
429- Rate limiting500,502,503,504- Server errors
For environments where you want to generate tokens separately from making API calls, use the TokenProvider pattern:
import com.coinbase.cdp.auth.CdpTokenGenerator;
import com.coinbase.cdp.auth.CdpTokenRequest;
import com.coinbase.cdp.auth.TokenProvider;
// Create a token generator (typically on your backend)
CdpTokenGenerator tokenGenerator = new CdpTokenGenerator(
apiKeyId, apiKeySecret, Optional.of(walletSecret)
);
// Generate tokens for a specific request
CdpTokenRequest tokenRequest = CdpTokenRequest.builder()
.requestMethod("POST")
.requestPath("/platform/v2/evm/accounts")
.requestHost("api.cdp.coinbase.com")
.includeWalletAuthToken(true)
.requestBody(new CreateEvmAccountRequest().name("my-account"))
.build();
TokenProvider tokens = tokenGenerator.generateTokens(tokenRequest);
// Use tokens with the client (typically on the edge/client)
try (CdpClient cdp = CdpClient.builder()
.tokenProvider(tokens)
.build()) {
var account = cdp.evm().createAccount(
new CreateEvmAccountRequest().name("my-account")
);
}Important: Wallet JWTs are request-specific. Each write operation needs its own TokenProvider because the wallet JWT includes the HTTP method, path, and body hash.
For advanced use cases, you can access the generated OpenAPI classes directly:
import com.coinbase.cdp.openapi.api.EvmAccountsApi;
import com.coinbase.cdp.openapi.api.SolanaAccountsApi;
import com.coinbase.cdp.openapi.api.PolicyEngineApi;
try (CdpClient cdp = CdpClient.create()) {
// Get the configured ApiClient
var apiClient = cdp.getApiClient();
// Create API instances
EvmAccountsApi evmApi = new EvmAccountsApi(apiClient);
SolanaAccountsApi solanaApi = new SolanaAccountsApi(apiClient);
PolicyEngineApi policiesApi = new PolicyEngineApi(apiClient);
// Read operations
var accounts = evmApi.listEvmAccounts(null, null, null);
// Write operations require wallet JWT
var request = new CreateEvmAccountRequest().name("my-account");
String walletJwt = cdp.generateWalletJwt("POST", "/v2/evm/accounts", request);
var account = evmApi.createEvmAccount(walletJwt, null, request);
}| API Class | Purpose |
|---|---|
EvmAccountsApi |
EVM account management (create, list, sign) |
EvmSmartAccountsApi |
EVM smart account operations (ERC-4337) |
EvmSwapsApi |
Token swap operations on EVM chains |
SolanaAccountsApi |
Solana account management |
PolicyEngineApi |
Policy management for operation controls |
FaucetsApi |
Request testnet funds |
OnchainDataApi |
Query on-chain data |
EndUserAccountManagementApi |
End user CRUD operations |
EndUserAccountsApi |
End user transaction operations |
See the com.coinbase.cdp.openapi.api package for all available APIs.
The SDK exposes JWT generation utilities for custom integrations:
import com.coinbase.cdp.auth.JwtGenerator;
import com.coinbase.cdp.auth.JwtOptions;
import com.coinbase.cdp.auth.WalletJwtGenerator;
import com.coinbase.cdp.auth.WalletJwtOptions;
// Generate JWT for REST API
JwtOptions options = JwtOptions.builder("key-id", "key-secret")
.requestMethod("GET")
.requestHost("api.cdp.coinbase.com")
.requestPath("/platform/v2/evm/accounts")
.expiresIn(120)
.build();
String jwt = JwtGenerator.generateJwt(options);
// Generate JWT for WebSocket (no URI claims)
JwtOptions wsOptions = JwtOptions.builder("key-id", "key-secret").build();
String wsJwt = JwtGenerator.generateJwt(wsOptions);
// Generate Wallet JWT for write operations
WalletJwtOptions walletOptions = new WalletJwtOptions(
walletSecret,
"POST",
"api.cdp.coinbase.com",
"/platform/v2/evm/accounts",
Map.of("name", "my-account")
);
String walletJwt = WalletJwtGenerator.generateWalletJwt(walletOptions);The SDK uses exceptions from the generated OpenAPI client:
try {
var account = cdp.evm().createAccount(
new CreateEvmAccountRequest().name("my-account")
);
} catch (com.coinbase.cdp.openapi.ApiException e) {
System.err.println("API error: " + e.getCode() + " - " + e.getMessage());
System.err.println("Response body: " + e.getResponseBody());
}- Multi-blockchain support: EVM chains and Solana
- High-level API: Namespace clients (
cdp.evm(),cdp.solana(),cdp.policies(),cdp.endUser()) - Server-managed accounts: Create and manage accounts on CDP
- Smart accounts: ERC-4337 account abstraction support
- End user management: Create, manage, and perform delegated operations on end users
- Policy engine: Define operation controls
- Dual key support: EC (ES256) and Ed25519 (EdDSA) authentication
- Automatic auth: API key JWT headers added automatically
- Configurable retries: Exponential backoff with jitter
- TokenProvider pattern: Flexible authentication for serverless deployments
make build# Run unit tests
make test
# Run E2E tests (requires API credentials)
make test-e2e# Check code style
make lint
# Fix code style issues
make lint-fixmake clientmake docsWorking examples are available in the examples/java directory:
| Task | Command |
|---|---|
| Quickstart | ./gradlew runQuickstart |
| Create EVM account | ./gradlew runCreateEvmAccount |
| List EVM accounts | ./gradlew runListEvmAccounts |
| Sign message | ./gradlew runSignMessage |
| Request faucet | ./gradlew runRequestFaucet |
| Transfer tokens | ./gradlew runTransfer |
| TokenProvider pattern | ./gradlew runSignTypedDataWithTokenProvider |
| Retry configuration | ./gradlew runRetryConfiguration |
| Create Solana account | ./gradlew runCreateSolanaAccount |
| Solana transfer | ./gradlew runSolanaTransfer |
Run ./gradlew listExamples for the full list.
MIT License - see LICENSE