Note
We are trialing a Discord server for developers building with Chargebee. Limited spots are open on a first-come basis. Join here if interested.
This is the official Java library for integrating with Chargebee.
- ๐ For a complete reference of available APIs, check out our API Documentation.
- ๐งช To explore and test API capabilities interactively, head over to our API Explorer.
Library versions
The versioning scheme of this library is inspired by SemVer and the format is v{MAJOR}.{MINOR}.{PATCH}. For example, v4.0.0 and v3.0.0 are valid library versions.
The following table provides some details for each major version:
| Library major version | Status | Compatible API versions | Branch |
|---|---|---|---|
| v4 | Active | v2 | v4 |
| v3 | Active | v2 | v3 |
| v2 | Inactive | v2 and v1 | chargebee-v2 |
| v1 | Inactive | v1 | chargebee-v1 |
A couple of terms used in the above table are explained below:
- Status: The current development status for the library version. Beta versions are feature-complete but may have breaking changes. Active major versions are currently being maintained and continue to get backward-compatible changes. Inactive versions no longer receive any updates.
- Branch: The branch in this repository containing the source code for the latest release of the library version. Every version of the library has been tagged. You can check out the source code for any version using its tag.
๐ด Attention: The support for v3 will eventually be discontinued on December 31st 2026 and will no longer receive any further updates. We strongly recommend upgrading to v4 as soon as possible. See our migration guide for detailed upgrade instructions.
๐ก Rest assured: Your existing v3 integrations will continue to function indefinitely. After December 31st 2026, v3 will no longer receive updates for new API features, but all current functionality will remain operational.
๐ Looking for v3 SDK documentation? Please refer to the
v3branch for v3 SDK usage and documentation.
Note: See the changelog for a history of changes.
Install the library
Requirement
- Java 1.8 or later.
Installation
The SDK provides a modern, immutable client with enhanced type safety and improved developer experience.
Gradle (Kotlin DSL)
dependencies {
implementation("com.chargebee:chargebee-java:{MAJOR}.{MINOR}.{PATCH}")
}Maven
<dependency> <groupId>com.chargebee</groupId> <artifactId>chargebee-java</artifactId> <version>{MAJOR}.{MINOR}.{PATCH}</version> </dependency>
Dependencies
The Chargebee Java SDK uses Gson 2.13.2 for JSON processing. Gson is declared as a regular dependency of the SDK and is therefore included transitively when the SDK is added to a project.
Gson version conflicts
Projects that already depend on a different version of Gson may encounter version conflicts. The build tool resolves a single version based on its dependency resolution strategy, which can lead to mismatches.
Gradle selects the highest version by default. If the project uses an older Gson version, Gradle will resolve to the highest version (2.13.2) by default. To pin a specific version:
configurations.all {
resolutionStrategy {
force("com.google.code.gson:gson:2.13.2")
}
}Maven uses the nearest-wins strategy, meaning a direct dependency declared in the project takes precedence over the SDK's transitive dependency. If an older version is declared directly, it will override the SDK's version. To align versions, either upgrade the direct dependency or use <dependencyManagement>:
<dependencyManagement> <dependencies> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.13.2</version> </dependency> </dependencies> </dependencyManagement>
Minimum compatible Gson version: 2.8.6. The SDK relies on JsonParser.parseString(), which was introduced in Gson 2.8.6. Versions older than 2.8.6 will cause a NoSuchMethodError at runtime.
Recommended: Gson 2.10.1 or later is recommended for best compatibility. Projects unable to upgrade should verify that the resolved Gson version is at least 2.8.6.
Install JAR files
Obtain pre-built JAR files
You can find the JAR files for the library in the dist directory. To obtain the JAR files for a specific library version, check the dist directory within the source tree of the appropriate tag.
Build JAR files
Alternatively, you can build the JAR files by following the steps below:
- Checkout the appropriate version of the library source code.
For example, the following is valid:
- Clean and build using Maven.
Use the library
Quick Start
Create a client
import com.chargebee.v4.client.ChargebeeClient; ChargebeeClient client = ChargebeeClient.builder() .apiKey("cb_test_...") .siteName("acme") .build();
Create and list customers (sync)
import com.chargebee.v4.services.CustomerService; import com.chargebee.v4.models.customer.params.CustomerCreateParams; import com.chargebee.v4.models.customer.params.CustomerListParams; import com.chargebee.v4.models.customer.responses.CustomerCreateResponse; import com.chargebee.v4.models.customer.responses.CustomerListResponse; CustomerService customers = client.customers(); CustomerCreateResponse created = customers.create( CustomerCreateParams.builder() .firstName("Ada") .lastName("Lovelace") .email("ada@example.com") .billingAddress( CustomerCreateParams.BillingAddressParams.builder() .line1("50 Market St") .city("San Francisco") .state("CA") .zip("94105") .country("US") .build() ) .build() ); CustomerListResponse list = customers.list( CustomerListParams.builder() .limit(10) .email().startsWith("ada@") .build() );
Configure client with retries and timeouts
import com.chargebee.v4.internal.RetryConfig; ChargebeeClient client = ChargebeeClient.builder() .apiKey("cb_test_...") .siteName("acme") .retry( RetryConfig.builder() .enabled(true) .maxRetries(3) .baseDelayMs(500) .build() ) .timeout(10000, 60000) .debugLogging(true) .build();
Per-request options
import com.chargebee.v4.client.request.RequestOptions; CustomerService scoped = client.customers().withOptions( RequestOptions.builder() .header("Idempotency-Key", "req-123") .maxNetworkRetries(2) .build() );
Async support
import java.util.concurrent.CompletableFuture; import com.chargebee.v4.transport.Response; CompletableFuture<Response> future = client.getAsync("/customers"); future.thenAccept(resp -> { if (resp.isSuccessful()) { System.out.println(resp.getBodyAsString()); } });
Custom Field Filtering
Filter list operations by custom fields using type-safe filters (stringFilter(), numberFilter(), timestampFilter(), booleanFilter()):
CustomerListParams params = CustomerListParams.builder() .customField("cf_plan_tier").stringFilter().in("gold", "platinum") .customField("cf_is_vip").booleanFilter().is(true) .customField("cf_total_spent").numberFilter().gte(5000L) .build(); CustomerListResponse response = client.customers().list(params);
Exception Handling
The library provides a comprehensive exception hierarchy with strongly-typed error enums to handle different types of errors that may occur during API operations.
Exception Hierarchy
All Chargebee exceptions extend from ChargebeeException, which is an unchecked exception:
ChargebeeException (unchecked - extends RuntimeException)
โโโ ConfigurationException (setup/config errors)
โโโ TransportException (runtime API errors)
โโโ NetworkException (DNS failures, connection refused)
โโโ TimeoutException (connect/read timeouts)
โโโ HttpException (HTTP status code errors: 4xx, 5xx)
โโโ ClientErrorException (4xx errors)
โโโ ServerErrorException (5xx errors)
โโโ APIException (Chargebee API errors)
โโโ InvalidRequestException (validation errors)
โโโ PaymentException (payment-related errors)
โโโ OperationFailedException (business logic errors)
โโโ BatchAPIException (batch operation errors)
โโโ UbbBatchIngestionInvalidRequestException (batch ingestion errors)
Exception Types
ChargebeeException: Base exception for all SDK errors - catch-all for any Chargebee SDK errorConfigurationException: Thrown when SDK configuration is invalid (missing API key, invalid URL, etc.)TransportException: Base exception for all transport-layer failures (network issues, timeouts, etc.)HttpException: Thrown for HTTP error status codes (4xx, 5xx) - contains status code and responseClientErrorException: HTTP 4xx client errors (bad request, unauthorized, not found, etc.)ServerErrorException: HTTP 5xx server errors (internal server error, service unavailable, etc.)APIException: Base exception for Chargebee API errors - includes error type, API error code, and parametersInvalidRequestException: Invalid parameters, missing required fields, or validation errors (type:invalid_request)PaymentException: Payment failures such as card declined, insufficient funds, etc. (type:payment)OperationFailedException: Business logic violations or state conflicts (type:operation_failed)BatchAPIException: Errors specific to batch API operationsUbbBatchIngestionInvalidRequestException: Errors specific to UBB batch ingestion operations
Strongly-Typed Error Enums
The SDK provides strongly-typed enums for error handling, making it easier to write type-safe error handling code:
ErrorType Enum
Represents the type of error returned by the API:
import com.chargebee.v4.exceptions.ErrorType; // Available values: ErrorType.INVALID_REQUEST // Validation and request errors ErrorType.PAYMENT // Payment-related errors ErrorType.OPERATION_FAILED // Business logic errors ErrorType.UNTYPED // Untyped errors ErrorType._UNKNOWN // Unknown/new error types (forward compatibility)
Per-HTTP-Status API Error Code Enums
Each HTTP status code has its own enum with specific error codes:
| Enum | HTTP Status | Example Error Codes |
|---|---|---|
BadRequestApiErrorCode |
400 | DUPLICATE_ENTRY, INVALID_REQUEST, PAYMENT_PROCESSING_FAILED, PARAM_WRONG_VALUE |
UnauthorizedApiErrorCode |
401 | API_AUTHENTICATION_FAILED, BASIC_AUTHENTICATION_FAILED |
ForbiddenApiErrorCode |
403 | REQUEST_BLOCKED, API_AUTHORIZATION_FAILED |
NotFoundApiErrorCode |
404 | RESOURCE_NOT_FOUND, SITE_NOT_FOUND |
ConflictApiErrorCode |
409 | INVALID_STATE_FOR_REQUEST |
TooManyRequestsApiErrorCode |
429 | REQUEST_LIMIT_EXCEEDED, OPERATION_LIMIT_EXCEEDED |
InternalServerErrorApiErrorCode |
500 | INTERNAL_ERROR, INTERNAL_TEMPORARY_ERROR |
ServiceUnavailableApiErrorCode |
503 | SITE_NOT_READY, SITE_MIGRATING, SITE_UNDER_MAINTENANCE |
All enums include an _UNKNOWN value for forward compatibility when new error codes are added by the API.
Exception Handling Examples
Basic exception handling with enums
import com.chargebee.v4.client.ChargebeeClient; import com.chargebee.v4.exceptions.APIException; import com.chargebee.v4.exceptions.PaymentException; import com.chargebee.v4.exceptions.codes.ApiErrorCode; import com.chargebee.v4.exceptions.codes.BadRequestApiErrorCode; import com.chargebee.v4.models.customer.responses.CustomerCreateResponse; import com.chargebee.v4.services.CustomerService; import com.chargebee.v4.exceptions.*; import com.chargebee.v4.models.customer.params.CustomerCreateParams; CustomerService customers = client.customers(); try { CustomerCreateResponse created = customers.create( CustomerCreateParams.builder() .email("invalid-email") // Invalid email format .build() ); } catch (InvalidRequestException e) { // getApiErrorCode() returns a strongly-typed ApiErrorCode enum ApiErrorCode errorCode = e.getApiErrorCode(); // Cast to specific enum based on HTTP status code if (errorCode instanceof BadRequestApiErrorCode) { BadRequestApiErrorCode code = (BadRequestApiErrorCode) errorCode; if (code == BadRequestApiErrorCode.DUPLICATE_ENTRY) { System.err.println("Resource already exists!"); } else if (code == BadRequestApiErrorCode.PARAM_WRONG_VALUE) { System.err.println("Invalid parameter: " + e.getParams()); } } } catch (PaymentException e) { ApiErrorCode errorCode = e.getApiErrorCode(); if (errorCode instanceof BadRequestApiErrorCode) { BadRequestApiErrorCode code = (BadRequestApiErrorCode) errorCode; if (code == BadRequestApiErrorCode.PAYMENT_PROCESSING_FAILED) { System.err.println("Payment failed. Please try again."); } else if (code == BadRequestApiErrorCode.PAYMENT_METHOD_NOT_PRESENT) { System.err.println("No payment method on file."); } } } catch (APIException e) { // Handle other API errors System.err.println("API error: " + e.getMessage()); System.err.println("Error type: " + e.getErrorType()); } catch (TransportException e) { // Handle network/transport errors System.err.println("Transport error: " + e.getMessage()); }
Using switch with ErrorType enum
try { // API operation } catch (APIException e) { switch (e.getErrorType()) { case INVALID_REQUEST: System.err.println("Invalid request: " + e.getMessage()); break; case PAYMENT: System.err.println("Payment error: " + e.getMessage()); break; case OPERATION_FAILED: System.err.println("Operation failed: " + e.getMessage()); break; default: System.err.println("Unknown error type: " + e.getType()); } }
Handling specific error codes
import com.chargebee.v4.exceptions.*; import com.chargebee.v4.exceptions.codes.ApiErrorCode; import com.chargebee.v4.exceptions.codes.BadRequestApiErrorCode; try { client.subscriptions().create(params); } catch (APIException e) { ApiErrorCode errorCode = e.getApiErrorCode(); // Check if it's a BadRequest error code if (errorCode instanceof BadRequestApiErrorCode) { BadRequestApiErrorCode code = (BadRequestApiErrorCode) errorCode; switch (code) { case DUPLICATE_ENTRY: System.err.println("Resource already exists"); break; case RESOURCE_LIMIT_EXHAUSTED: System.err.println("Limit reached, please upgrade your plan"); break; case PAYMENT_PROCESSING_FAILED: System.err.println("Payment failed, please update payment method"); break; case _UNKNOWN: // Unknown error code - use raw value for logging System.err.println("Unknown error code: " + e.getApiErrorCodeRaw()); break; default: System.err.println("Error: " + e.getMessage()); } } }
Checking for unknown error types (forward compatibility)
try { // API operation } catch (APIException e) { ErrorType errorType = e.getErrorType(); if (!errorType.isKnown()) { // New error type added by API that SDK doesn't know about yet System.err.println("New error type encountered: " + e.getType()); // Log for investigation, but handle gracefully } ApiErrorCode errorCode = e.getApiErrorCode(); if (errorCode != null && !errorCode.isKnown()) { // New error code - handle gracefully using raw value System.err.println("New error code: " + e.getApiErrorCodeRaw()); } }
Handling HTTP-level errors
import com.chargebee.v4.exceptions.ClientErrorException; import com.chargebee.v4.exceptions.ServerErrorException; import com.chargebee.v4.exceptions.HttpException; try { CustomerCreateResponse response = client.customers().create(params); } catch (ClientErrorException e) { // Handle 4xx client errors if (e.isUnauthorized()) { System.err.println("Authentication failed. Check your API key."); } else if (e.isNotFound()) { System.err.println("Resource not found."); } else if (e.isTooManyRequests()) { System.err.println("Rate limit exceeded. Retry after some time."); } else { System.err.println("Client error: " + e.getStatusCode()); } } catch (ServerErrorException e) { // Handle 5xx server errors (often retryable) if (e.isRetryable()) { System.err.println("Server error. Consider retrying: " + e.getMessage()); } } catch (HttpException e) { System.err.println("HTTP error: " + e.getStatusCode()); } catch (Exception e) { throw new RuntimeException(e); }
Error Response Attributes
The APIException class provides typed access to all error response attributes:
| Attribute | Method | Description |
|---|---|---|
message |
getMessage() |
Descriptive error information (for developer consumption, not for end users) |
type |
getType() / getErrorType() |
Error type grouping: payment, invalid_request, operation_failed |
api_error_code |
getApiErrorCode() / getApiErrorCodeRaw() |
Strongly-typed enum (ApiErrorCode) or raw string for error handling |
param |
getParam() / getParams() |
Parameter name(s) if error is parameter-specific |
error_cause_id |
getErrorCauseId() |
Chargebee-defined code for standardizing errors across gateways |
Extracting detailed error information
try { // API operation } catch (APIException e) { // Get HTTP status code int statusCode = e.getStatusCode(); // Get error type as enum (type-safe) ErrorType errorType = e.getErrorType(); // Get error type as raw string String type = e.getType(); // Get API error code as typed enum ApiErrorCode apiErrorCode = e.getApiErrorCode(); // Get API error code as raw string (for logging) String apiErrorCodeRaw = e.getApiErrorCodeRaw(); // Get error message (for developer consumption) String message = e.getMessage(); // Get parameter name(s) that caused the error String param = e.getParam(); // Single param (convenience) List<String> params = e.getParams(); // All params // Get error cause ID (for gateway error standardization) String errorCauseId = e.getErrorCauseId(); // Get full JSON response for debugging String jsonResponse = e.getJsonResponse(); // Get full HTTP response object Response response = e.getResponse(); System.err.println("Error details: " + e.toString()); }
Handling gateway errors with error_cause_id
try { // Payment operation } catch (PaymentException e) { // error_cause_id helps standardize errors across different payment gateways String errorCauseId = e.getErrorCauseId(); if (errorCauseId != null) { // Use error_cause_id for consistent handling across gateways System.err.println("Gateway error cause: " + errorCauseId); } // Check the specific API error code using typed enum ApiErrorCode errorCode = e.getApiErrorCode(); if (errorCode instanceof BadRequestApiErrorCode) { BadRequestApiErrorCode code = (BadRequestApiErrorCode) errorCode; if (code == BadRequestApiErrorCode.PAYMENT_PROCESSING_FAILED) { // Handle payment failure } } }
Async exception handling
Important: When using async methods, exceptions are wrapped in a
java.util.concurrent.CompletionException. Unlike sync methods that throwChargebeeExceptiondirectly, async methods deliver errors throughCompletableFuture's.exceptionally()or.handle()callbacks, where the original exception is available viathrowable.getCause(). Always unwrap theCompletionExceptionto access the underlyingChargebeeException(e.g.,InvalidRequestException,APIException).
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; CompletableFuture<CustomerCreateResponse> futureCustomer = customers.createAsync(params); futureCustomer .thenAccept(response -> { System.out.println("Customer created: " + response.getCustomer().getId()); }) .exceptionally(throwable -> { // Unwrap CompletionException to get the actual ChargebeeException Throwable cause = throwable instanceof CompletionException ? throwable.getCause() : throwable; if (cause instanceof InvalidRequestException) { InvalidRequestException e = (InvalidRequestException) cause; ApiErrorCode errorCode = e.getApiErrorCode(); if (errorCode instanceof BadRequestApiErrorCode) { BadRequestApiErrorCode code = (BadRequestApiErrorCode) errorCode; if (code == BadRequestApiErrorCode.DUPLICATE_ENTRY) { System.err.println("Customer already exists"); } } else { System.err.println("Validation error: " + e.getMessage()); } } else if (cause instanceof APIException) { APIException e = (APIException) cause; System.err.println("API error: " + e.getApiErrorCodeRaw()); } else { System.err.println("Unexpected error: " + cause.getMessage()); } return null; });
If you prefer blocking on the result, use a try-catch around .join() or .get():
try { CustomerCreateResponse response = customers.createAsync(params).join(); System.out.println("Customer created: " + response.getCustomer().getId()); } catch (CompletionException e) { // Unwrap to get the original ChargebeeException Throwable cause = e.getCause(); if (cause instanceof InvalidRequestException) { System.err.println("Validation error: " + cause.getMessage()); } else if (cause instanceof APIException) { System.err.println("API error: " + ((APIException) cause).getApiErrorCodeRaw()); } else { throw e; // Re-throw unexpected errors } }
Retry Handling
Chargebee's SDK includes built-in retry logic to handle temporary network issues and server-side errors. This feature is disabled by default but can be enabled when needed.
Key features include:
- Automatic retries for specific HTTP status codes: Retries are automatically triggered for status codes
500,502,503, and504. - Exponential backoff: Retry delays increase exponentially to prevent overwhelming the server.
- Rate limit management: If a
429 Too Many Requestsresponse is received with aRetry-Afterheader, the SDK waits for the specified duration before retrying.Note: Exponential backoff and max retries do not apply in this case.
- Customizable retry behavior: Retry logic can be configured using the
retryConfigparameter in the environment configuration.
Example: Customizing Retry Logic
You can enable and configure the retry logic by passing a retryConfig object when initializing the Chargebee environment:
import com.chargebee.Environment; public class Sample { public static void main(String[] args) throws Exception { Environment.configure("{site}", "{site_api_key}"); Environment.defaultConfig().updateRetryConfig( new com.chargebee.internal.RetryConfig( true, 3, 500, new java.util.HashSet<>(java.util.Arrays.asList(500)) ) ); // ... your Chargebee API operations ... } }
Example: Rate Limit retry logic
You can enable and configure the retry logic for rate-limit by passing a retryConfig object when initializing the Chargebee environment:
import com.chargebee.Environment; public class Sample { public static void main(String[] args) throws Exception { Environment.configure("{site}", "{site_api_key}"); Environment.defaultConfig().updateRetryConfig( new com.chargebee.internal.RetryConfig( true, 3, 500, new java.util.HashSet<>(java.util.Arrays.asList(429)) ) ); // ... your Chargebee API operations ... } }
Features
SDK Features
- Immutable
ChargebeeClientwith fluent builder - Direct property naming (e.g.,
.apiKey(),.siteName()) - Type-safe request models and responses
- Sync and async APIs with retry/backoff
- Per-request options and headers
- Enhanced error handling and debugging
Build & Test
- Java 8+
./gradlew build- Build project./gradlew test- Run tests
ProGuard / R8 Configuration
If you're using ProGuard or R8, add the following rules to prevent the SDK from being obfuscated:
# Chargebee SDK - preserve all public API classes and models
-keep class com.chargebee.v4.** { *; }
-keepclassmembers class com.chargebee.v4.** { *; }
# Keep all enum values
-keepclassmembers enum com.chargebee.v4.** { *; }
These rules ensure that reflection-based serialization/deserialization and the exception hierarchy work correctly at runtime.
Contribution
You may contribute patches to any of the Active versions of this library. To do so, raise a PR against the respective branch.
If you find something amiss, you are welcome to create an issue.
Documentation
- Migration Guide - Upgrade instructions between versions
The API documentation for the Java library can be found in our API reference.
License
See the LICENSE.