{"id":27151394,"url":"https://github.com/checkout/checkout-sdk-java","last_synced_at":"2026-03-12T13:04:25.911Z","repository":{"id":37086831,"uuid":"192770578","full_name":"checkout/checkout-sdk-java","owner":"checkout","description":"Checkout.com SDK for Java","archived":false,"fork":false,"pushed_at":"2025-07-02T14:48:15.000Z","size":3605,"stargazers_count":26,"open_issues_count":2,"forks_count":30,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-07-02T15:45:27.848Z","etag":null,"topics":["java","sdk"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/checkout.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-06-19T16:44:48.000Z","updated_at":"2025-07-02T14:30:10.000Z","dependencies_parsed_at":"2023-10-14T14:07:43.642Z","dependency_job_id":"4b1c0e02-92a5-4a29-829e-0a8b78375cc6","html_url":"https://github.com/checkout/checkout-sdk-java","commit_stats":null,"previous_names":[],"tags_count":119,"template":false,"template_full_name":null,"purl":"pkg:github/checkout/checkout-sdk-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fcheckout-sdk-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fcheckout-sdk-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fcheckout-sdk-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fcheckout-sdk-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/checkout","download_url":"https://codeload.github.com/checkout/checkout-sdk-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fcheckout-sdk-java/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263421460,"owners_count":23464012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","sdk"],"created_at":"2025-04-08T14:40:20.620Z","updated_at":"2026-02-10T14:05:36.765Z","avatar_url":"https://github.com/checkout.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Checkout.com Java SDK\n\n[![build-status](https://github.com/checkout/checkout-sdk-java/workflows/build-master/badge.svg)](https://github.com/checkout/checkout-sdk-java/actions/workflows/build-master.yml)\n![CodeQL](https://github.com/checkout/checkout-sdk-java/workflows/CodeQL/badge.svg)\n\n![build-status](https://github.com/checkout/checkout-sdk-java/workflows/build-release/badge.svg)\n[![GitHub release](https://img.shields.io/github/release/checkout/checkout-sdk-java.svg)](https://GitHub.com/checkout/checkout-sdk-java/releases/)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.checkout/checkout-sdk-java/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.checkout/checkout-sdk-java/)\n\n[![GitHub license](https://img.shields.io/github/license/checkout/checkout-sdk-java.svg)](https://github.com/checkout/checkout-sdk-java/blob/master/LICENSE.md)\n\n## Getting started\n\n\u003e **Version 6.0.0 is here!**\n\u003e  \u003cbr/\u003e\u003cbr/\u003e\n\u003e We improved the initialization of SDK making it easier to understand the available options. \u003cbr/\u003e\n\u003e Now `NAS` accounts are the default instance for the SDK and `ABC` structure was moved to a `previous` prefixes. \u003cbr/\u003e\n\u003e If you have been using this SDK before, you may find the following important changes:\n\u003e * Marketplace module was moved to Accounts module, same for classes and references.\n\u003e * In most cases, IDE can help you determine from where to import, but if you’re still having issues don't hesitate to open a [ticket](https://github.com/checkout/checkout-sdk-java/issues/new/choose).\n\n#### Gradle\n\n```groovy\ndependencies {\n    implementation 'com.checkout:checkout-sdk-java:\u003cversion\u003e'\n}\n```\n\n## Building from source\n\nOnce you check out the code from GitHub, the project can be built using Gradle:\n\n```\ngradlew build\n\n# skip tests\ngradlew build -x test\n```\n\nThe execution of integration tests require the following environment variables set in your system:\n\n* For default account systems (NAS): `CHECKOUT_DEFAULT_PUBLIC_KEY` \u0026 `CHECKOUT_DEFAULT_SECRET_KEY`\n* For default account systems (OAuth): `CHECKOUT_DEFAULT_OAUTH_CLIENT_ID` \u0026 `CHECKOUT_DEFAULT_OAUTH_CLIENT_SECRET`\n* For Previous account systems (ABC): `CHECKOUT_PREVIOUS_PUBLIC_KEY` \u0026 `CHECKOUT_PREVIOUS_SECRET_KEY`\n\n#### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.checkout\u003c/groupId\u003e\n    \u003cartifactId\u003echeckout-sdk-java\u003c/artifactId\u003e\n    \u003cversion\u003eversion\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### :rocket: Please check in [GitHub releases](https://github.com/checkout/checkout-sdk-java/releases) for all the versions available.\n\n### :book: Checkout our official documentation.\n\n* [Official Docs (Default)](https://docs.checkout.com/)\n* [Official Docs (Previous)](https://docs.checkout.com/previous)\n\n### :books: Check out our official API documentation guide, where you can also find more usage examples.\n\n* [API Reference (Default)](https://api-reference.checkout.com/)\n* [API Reference (Previous)](https://api-reference.checkout.com/previous)\n\n\n## How to use the SDK\n\nThis SDK can be used with two different pair of API keys provided by Checkout. However, using different API keys implies using specific API features. \u003c/br\u003e\nPlease find in the table below the types of keys that can be used within this SDK.\n\n| Account System | Public Key (example)                    | Secret Key (example)                    |\n|----------------|-----------------------------------------|-----------------------------------------|\n| Default        | pk_abcdef123456ghijkl789mnopqr          | sk_123456ghijklm7890abcdefxyz           |\n| Previous       | pk_12345678-abcd-efgh-ijkl-mnopqrstuvwx | sk_abcdef12-3456-ghij-klmn-opqrstuvwxyz |\n\nNote: sandbox keys have a `sbox_` or `test_` identifier, for Default and Previous accounts respectively.\n\nIf you don't have your own API keys, you can sign up for a test account [here](https://www.checkout.com/get-test-account).\n\n**PLEASE NEVER SHARE OR PUBLISH YOUR CHECKOUT CREDENTIALS.**\n\n### Default\n\nDefault keys client instantiation can be done as follows:\n\n```java\nimport com.checkout.CheckoutApi;\n\npublic static void main(String[] args) {\n    \n    final CheckoutApi checkoutApi = CheckoutSdk.builder()\n            .staticKeys()\n            .publicKey(\"public_key\")  // optional, only required for operations related with tokens\n            .secretKey(\"secret_key\")\n            .environment(Environment.PRODUCTION)  // required\n            .environmentSubdomain(\"subdomain\") // optional, Merchant-specific DNS name\n            .executor() // optional for a custom Executor Service\n            .build();\n    \n    final PaymentsClient client = checkoutApi.paymentsClient();\n    \n    final CompletableFuture\u003cRefundResponse\u003e refundPayment = client.refundPayment(\"payment_id\");\n}\n```\n\n### Default OAuth\n\nThe SDK supports client credentials OAuth, when initialized as follows:\n\n```java\nimport com.checkout.CheckoutApi;\n\npublic static void main(String[] args) {\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .oAuth()\n        .clientCredentials(\"client_id\", \"client_secret\")\n        // for a specific authorization endpoint\n        //.clientCredentials(new URI(\"https://access.sandbox.checkout.com/connect/token\"), \"client_id\", \"client_secret\")\n        .scopes(OAuthScope.GATEWAY, OAuthScope.VAULT, OAuthScope.FX)\n        .environment(Environment.PRODUCTION)  // required\n        .environmentSubdomain(\"subdomain\") // optional, Merchant-specific DNS name\n        .executor() // optional for a custom Executor Service\n        .build();\n\nfinal PaymentsClient client = checkoutApi.paymentsClient();\n\nfinal CompletableFuture\u003cRefundResponse\u003e refundPayment = client.refundPayment(\"payment_id\");\n}\n```\n\n### Previous\n\nIf your pair of keys matches the Previous type, this is how the SDK should be used:\n\n```java\nimport com.checkout.previous.CheckoutApi;\n\npublic static void main(String[] args) {\n    final CheckoutApi checkoutApi = CheckoutSdk.builder()\n            .previous()\n            .staticKeys()\n            .publicKey(\"public_key\")  // optional, only required for operations related with tokens\n            .secretKey(\"secret_key\")\n            .environment(Environment.PRODUCTION)  // required\n            .environmentSubdomain(\"subdomain\") // optional, Merchant-specific DNS name\n            .executor() // optional for a custom Executor Service\n            .build();\n    \n    final PaymentsClient client = checkoutApi.paymentsClient();\n    \n    final CompletableFuture\u003cRefundResponse\u003e refundPayment = client.refundPayment(\"payment_id\");\n        }\n```\n\n## Logging\n\nThe SDK supports SLF4J as logger provider, you need to provide your configuration file through `resources` folder.\n\n## Exception handling\n\nAll the API responses that do not fall in the 2** status codes will cause a `CheckoutApiException`. The exception encapsulates\nthe `responseHeaders`, `httpStatusCode` and a map of `errorDetails`, if available.\n\n## Telemetry\nRequest telemetry is enabled by default in the Java SDK. Request latency is included in the telemetry data. Recording the request latency allows Checkout.com to continuously monitor and improve the merchant experience.\n\nRequest telemetry can be disabled by opting out during CheckoutSdk builder step:\n```java\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)\n        .recordTelemetry(false)\n        .build();\n```\n\n## Asynchronous and Synchronous Operations\n\nThe SDK provides flexibility in how you handle API operations by supporting both asynchronous and synchronous execution modes. You can freely use the async and sync functions of each client, and they will return **CompletableFuture\u003cResponseObject\u003e** or **ResponseObject** respectively, both functions are existing in all client, maintaining a consistent API interface. For example, the flow client looks like:\n\n```java\n        public interface FlowClient {\n\n        CompletableFuture\u003cPaymentSessionResponse\u003e requestPaymentSession(PaymentSessionRequest paymentSessionRequest);\n\n        CompletableFuture\u003cSubmitPaymentSessionResponse\u003e submitPaymentSessions(\n                String paymentId,\n                SubmitPaymentSessionRequest submitPaymentSessionRequest\n        );\n\n        CompletableFuture\u003cPaymentSessionWithPaymentResponse\u003e requestPaymentSessionWithPayment(\n                PaymentSessionWithPaymentRequest paymentSessionRequest\n        );\n\n        // Synchronous methods\n        PaymentSessionResponse requestPaymentSessionSync(PaymentSessionRequest paymentSessionRequest);\n\n        SubmitPaymentSessionResponse submitPaymentSessionsSync(\n                String paymentId,\n                SubmitPaymentSessionRequest submitPaymentSessionRequest\n        );\n\n        PaymentSessionWithPaymentResponse requestPaymentSessionWithPaymentSync(\n                PaymentSessionWithPaymentRequest paymentSessionRequest\n        );\n        }\n```\n\nThe default operation mode of the SDK is async, so you can use async and sync functions freely, or combine them.\n\n### Aync/Sync Operation Mode\n\nThe SDK can be configured to operate in two different modes:\n\n#### Asynchronous Mode (Default)\n- **Configuration**: `synchronous(false)` or omit the setting (default)\n- **Behavior**: HTTP requests are executed asynchronously using the configured executor (except the specific sync methods)\n- **Transport**: Uses `Transport.invoke()` and `Transport.submitFile()` methods\n- **Resilience**: Resilience4j patterns are **NOT** supported in async mode\n- **Performance**: Non-blocking execution\n- **Return**: CompletableFuture\u003cResponseObject\u003e\n\n#### Synchronous Mode\n- **Configuration**: `synchronous(true)`\n- **Behavior**: HTTP requests are executed synchronously, even async ops will be executed synchronous is this mode is activated!!!\n- **Transport**: Uses `Transport.invokeSync()` and `Transport.submitFileSync()` methods  \n- **Resilience**: Full Resilience4j support (retry, rate limiter, circuit breaker)\n- **Performance**: Blocking execution with enhanced reliability patterns\n- **Return**: ResponseObject\n\n### How the Transport Layer Works\n\n#### Asynchronous Transport Behavior\n\nIn asynchronous mode, the transport layer:\n\n1. **Immediate Return**: Methods return `CompletableFuture` immediately\n2. **Async HTTP Execution**: HTTP calls are made asynchronously using Apache HttpClient\n3. **Thread Pool**: Uses the configured executor for CompletableFuture operations\n4. **Non-blocking**: The calling thread is NOT blocked during HTTP execution\n\n```java\n// Asynchronous mode configuration\nfinal CheckoutApi asyncApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)\n        .synchronous(false) // or omit (default)\n        .executor(Executors.newFixedThreadPool(20)) // Custom thread pool for async operations\n        .build();\n\n// Usage - returns immediately, HTTP call happens asynchronously\nCompletableFuture\u003cPaymentResponse\u003e future = asyncApi.paymentsClient().requestPayment(request);\n\n// Process result when available\nfuture.thenAccept(response -\u003e {\n    System.out.println(\"Payment ID: \" + response.getId());\n});\n```\n\n#### Synchronous Transport Behavior\n\nIn synchronous mode, the transport layer:\n\n1. **Blocking HTTP Call**: HTTP request is made synchronously with resilience patterns applied\n2. **Wrapped in CompletableFuture**: Result are returned directly as response objects when the call completes\n3. **Resilience4j Applied**: Retry, rate limiting and circuit breaker are applied during the synchronous HTTP call\n4. **Blocking**: The calling thread is blocked during HTTP execution until the call ends\n\n```java\n// Synchronous mode configuration with resilience\nfinal CheckoutApi syncApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)\n        .synchronous(true) // Enable synchronous mode\n        .resilience4jConfiguration(Resilience4jConfiguration.defaultConfiguration())\n        .executor(Executors.newFixedThreadPool(10)) // Thread pool for wrapping sync calls\n        .build();\n\n// Usage - HTTP call executes synchronously with resilience patterns\nPaymentResponse response = syncApi.paymentsClient().requestPaymentSync(request);\nSystem.out.println(\"Payment ID: \" + response.getId());\n```\n\n### Performance Characteristics\n\n#### Asynchronous Mode\n- **Pros**:\n  - Non-blocking execution\n  - Better resource utilization for I/O bound operations\n  - Lower memory footprint per request\n- **Cons**:\n  - No built-in resilience patterns\n  - Must implement retry logic manually\n  - More complex error handling\n\n#### Synchronous Mode  \n- **Pros**:\n  - Built-in resilience patterns (retry, rate limiting, circuit breaker)\n  - Simplified error handling with automatic retries\n  - Easier debugging and testing\n  - Transient error handling out-of-the-box\n- **Cons**:\n  - Blocking HTTP execution (but mitigated by executor wrapping)\n  - Higher resource usage due to resilience overhead\n\n### Choosing the Right Mode\n\n#### Use Asynchronous Mode When:\n- Implementing custom retry/resilience logic\n- Working with reactive programming patterns\n- Resource efficiency is critical\n- You need fine-grained control over error handling\n\n#### Use Synchronous Mode When:\n- You need robust error handling and retries\n- Reliability is more important than raw performance\n- You want built-in transient error handling\n- Implementing payment processing where consistency is critical\n\n### Example Comparison\n\n```java\n// Both modes have identical parameters for the interfaces\nPaymentRequest request = PaymentRequest.builder()\n        .source(cardSource)\n        .amount(1000L)\n        .currency(Currency.USD)\n        .build();\n\n// Asynchronous - fast return, manual error handling\nCompletableFuture\u003cPaymentResponse\u003e asyncResult = asyncApi.paymentsClient().requestPayment(request)\n        .exceptionally(throwable -\u003e {\n            // Manual retry logic if needed\n            if (shouldRetry(throwable)) {\n                return retryPayment(request);\n            }\n            throw new CompletionException(throwable);\n        });\n\n// Synchronous - built-in resilience, automatic retries\nPaymentResponse syncResult = syncApi.paymentsClient().requestPaymentSync(request);\n        // Resilience4j automatically handles retries for transient errors\n\n// Both return CompletableFuture - same API!\n```\n\n### Thread Pool Considerations\n\n- **Async Mode**: Executor primarily used for CompletableFuture operations, HTTP I/O is non-blocking\n- **Sync Mode**: Executor used to wrap synchronous operations, size should account for concurrent blocking calls\n- **Recommendation**: Use larger thread pools for sync mode to handle blocking operations\n\n## Custom Environment\n\nIn case that you want to use an integrator or mock server, you can specify your own configuration as follows:\n```java\nfinal CustomEnvironment environment = CustomEnvironment.builder()\n        .checkoutApi(create(\"https://the.base.uri/\")) // the uri for all Checkout operations\n        .oAuthAuthorizationApi(create(\"https://the.oauth.uri/connect/token\")) // the uri used for OAUTH authorization, only required for OAuth operations\n        .filesApi(create(\"https://the.files.uri/\")) // the uri used for Files operations, only required for Accounts module\n        .transfersApi(create(\"https://the.transfers.uri/\")) // the uri used for Transfer operations, only required for Transfers module\n        .balancesApi(create(\"https://the.balances.uri/\")) // the uri used for Balances operations, only required for Balances module\n        .sandbox(false) // flag to determine if Sanbox or Production configured, default false\n        .build();\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(environment)  // required\n        .executor(customHttpClient) // optional for a custom Executor Service\n        .build();\n```\n\nYou don't need to specify all the previous URI's, only the ones for the modules that you're going to use.\n\n## Custom HttpClient\n\nThe SDK allows you to customize the underlying HTTP client and executor configurations to meet your specific needs, such as custom connection pooling, proxy settings, timeout configurations, or multithreaded operations.\n\n### Basic HttpClient Configuration\n\nYou can provide your own `HttpClientBuilder` to customize HTTP connection properties:\n\n```java\nfinal HttpClientBuilder customHttpClient = HttpClientBuilder.create()\n        .setProxy(HttpHost.create(\"https://proxy\"))\n        .setConnectionTimeToLive(3, TimeUnit.SECONDS);\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)  // required\n        .environmentSubdomain(\"subdomain\") // optional, Merchant-specific DNS name\n        .httpClientBuilder(customHttpClient) // optional for a custom HttpClient\n        .build();\n```\n\n### Custom Executor\n\nYou can provide a custom `Executor` for handling asynchronous operations. By default, the SDK uses `ForkJoinPool.commonPool()`.\n\n```java\nfinal Executor customExecutor = Executors.newSingleThreadExecutor();\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)  // required\n        .executor(customExecutor) // optional for a custom Executor Service\n        .build();\n```\n\n### Multithreaded Configuration for High-Performance Applications\n\nFor applications requiring high concurrency and performance, you can configure both a custom executor with a larger thread pool and an HTTP client optimized for connection pooling:\n\n```java\n// Configure HttpClient for high concurrency\nfinal HttpClientBuilder multithreadedHttpClient = HttpClientBuilder.create()\n        .setMaxConnTotal(200)                             // Maximum total connections\n        .setMaxConnPerRoute(100)                          // Maximum connections per route/destination\n        .setConnectionTimeToLive(60, TimeUnit.SECONDS)    // Connection time-to-live\n        .evictIdleConnections(30, TimeUnit.SECONDS);      // Evict idle connections after 30 seconds\n\n// Configure a fixed thread pool executor\nfinal Executor multithreadedExecutor = Executors.newFixedThreadPool(100);\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)  // required\n        .executor(multithreadedExecutor)      // custom thread pool for async operations\n        .httpClientBuilder(multithreadedHttpClient) // custom HTTP client for connection pooling\n        .build();\n```\n\n**Configuration Options Explained:**\n\n- **`executor(Executor)`**: Configures the executor service for handling asynchronous operations. Default is `ForkJoinPool.commonPool()`.\n- **`httpClientBuilder(HttpClientBuilder)`**: Configures the Apache HttpClient settings. Default is `HttpClientBuilder.create()`.\n\n**Common HttpClient Settings:**\n\n- **`setMaxConnTotal(int)`**: Maximum number of total connections across all routes\n- **`setMaxConnPerRoute(int)`**: Maximum number of connections per specific route/destination\n- **`setConnectionTimeToLive(long, TimeUnit)`**: Connection lifetime before being evicted from the pool\n- **`evictIdleConnections(long, TimeUnit)`**: Time after which idle connections are evicted\n- **`setProxy(HttpHost)`**: Configure HTTP proxy server\n- **`setDefaultConnectionConfig(ConnectionConfig)`**: Set default connection configuration\n- **`setDefaultSocketConfig(SocketConfig)`**: Set socket configuration including timeouts\n\n## Advanced Customization for Different Throughput Requirements\n\nThis section provides specific configuration patterns for different application requirements, focusing on rate limiting and HTTP connection pool optimization.\n\n### HTTP Connection Pool Optimization by Throughput\n\nConfigure your HTTP connection pool based on your application's expected throughput and concurrency requirements.\n\n### Performance Tuning Guidelines\n\n#### Connection Pool Sizing Rules of Thumb\n\n- **MaxConnTotal**: Should be at least 2-3x your expected concurrent requests\n- **MaxConnPerRoute**: Usually 50-80% of MaxConnTotal for single-endpoint applications\n- **Thread Pool Size**: Should match or slightly exceed MaxConnPerRoute\n- **Connection TTL**: Shorter for high-load (10-30s), longer for low-load (60-300s)\n\n#### Monitoring and Observability\n\nWhen using custom configurations, monitor these metrics:\n\n- **Connection Pool Utilization**: Ensure pools aren't exhausted\n- **Request Rate**: Verify rate limiting effectiveness  \n- **Response Times**: Monitor impact of connection pooling\n- **Error Rates**: Track timeouts and connection failures\n- **Memory Usage**: Watch for connection pool memory impact\n\n## Retry Strategy and Resilience Configuration\n\nThe SDK includes built-in resilience patterns using the [Resilience4j](https://github.com/resilience4j/resilience4j) library to handle transient errors and improve reliability.\n\n### Supported Resilience Patterns\n\nThe SDK supports three main resilience patterns:\n- **Retry**: Automatically retries failed requests\n- **Rate Limiter**: Controls the rate of requests to prevent overloading\n- **Circuit Breaker**: Prevents cascading failures by temporarily stopping requests to failing services\n\n### Libraries Used\n\n- **Resilience4j Retry**: `io.github.resilience4j:resilience4j-retry:1.7.1` \n- **Resilience4j Rate Limiter**: `io.github.resilience4j:resilience4j-ratelimiter:1.7.1`\n- **Resilience4j Circuit Breaker**: `io.github.resilience4j:resilience4j-circuitbreaker:1.7.1`\n\n### How It Works\n\nThe resilience patterns are applied as decorators around your HTTP requests in the following order:\n1. **Rate Limiter** (if configured) - Controls request rate\n2. **Retry** (if configured) - Retries failed requests\n3. **Circuit Breaker** (if configured) - Wraps everything to prevent cascading failures (by default deactivated)\n\n### Transient Errors Handled\n\nThe retry mechanism can handle various types of transient errors, including:\n- Network connectivity issues (timeouts, connection refused)\n- HTTP 5xx server errors (500, 502, 503, 504)\n- Temporary service unavailability\n- Rate limiting responses (429)\n\n#### Individual Component Configuration\n\n```java\nfinal Resilience4jConfiguration resilience4jConfig = Resilience4jConfiguration.builder()\n        .withDefaultRetry()\n        // Deactivated by default\n        //.withDefaultRateLimiter()\n        // Deactivated by default\n        //.withDefaultCircuitBreaker()\n        .build();\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)\n        .synchronous(true)\n        .resilience4jConfiguration(resilience4jConfig)\n        .build();\n```\n\n### Custom Resilience Configuration\nDefault behavior: Asynchronous mode\nResilience4j: NOT applied by default\nTransport: Uses async methods (transport.invoke(), transport.submitFile())\nPerformance: Faster, non-blocking execution but no automatic retries\n\nTo enable synchronous mode with Resilience4j patterns, you need to explicitly set:\n```java\n    CheckoutSdk.builder()    .synchronous(true)\n```\nSo the SDK is designed to be async-first by default, which makes sense for most modern applications that prefer non-blocking operations.\n\n```java\n// SYNC transport (with Resilience4j)\n@Override\npublic Response invokeSync(...) {\n    // ... build request ...\n    final Supplier\u003cResponse\u003e callSupplier = () -\u003e performCall(...);\n    return executeWithResilience4j(callSupplier);  // ← Resilience4j applied here\n}\n\n// ASYNC transport (no Resilience4j)\n@Override\npublic CompletableFuture\u003cResponse\u003e invoke(...) {\n    return CompletableFuture.supplyAsync(() -\u003e {\n        // ... build request ...\n        return performCall(...);  // ← Direct call, no Resilience4j\n    }, executor);\n}\n```\n\n#### Custom Retry Configuration\n\n```java\nfinal RetryConfig retryConfig = RetryConfig.custom()\n        .maxAttempts(5)                                    // Maximum retry attempts\n        .waitDuration(Duration.ofMillis(1000))             // Wait time between retries\n        .retryOnException(throwable -\u003e \n            throwable instanceof CheckoutApiException \u0026\u0026   // Retry on API exceptions\n            ((CheckoutApiException) throwable).getHttpStatusCode() \u003e= 500) // Only 5xx errors\n        .build();\n\nfinal Resilience4jConfiguration resilience4jConfig = Resilience4jConfiguration.builder()\n        .withRetry(retryConfig)\n        .build();\n```\n\n#### Custom Rate Limiter Configuration\n(deactivated by default)\n\n```java\nfinal RateLimiterConfig rateLimiterConfig = RateLimiterConfig.custom()\n        .limitForPeriod(50)                                // 50 requests\n        .limitRefreshPeriod(Duration.ofSeconds(1))         // Per second\n        .timeoutDuration(Duration.ofSeconds(2))            // Wait up to 2 seconds for permission\n        .build();\n\nfinal Resilience4jConfiguration resilience4jConfig = Resilience4jConfiguration.builder()\n        .withRateLimiter(rateLimiterConfig)\n        .build();\n```\n\n#### Custom Circuit Breaker Configuration \n(deactivated by default)\n\n```java\nfinal CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()\n        .failureRateThreshold(60)                          // Open circuit at 60% failure rate\n        .waitDurationInOpenState(Duration.ofSeconds(60))   // Wait 60 seconds before trying again\n        .slidingWindowSize(20)                             // Consider last 20 requests\n        .minimumNumberOfCalls(10)                          // Minimum calls before evaluation\n        .permittedNumberOfCallsInHalfOpenState(5)          // Calls allowed in half-open state\n        .build();\n\nfinal Resilience4jConfiguration resilience4jConfig = Resilience4jConfiguration.builder()\n        .withCircuitBreaker(circuitBreakerConfig)\n        .build();\n```\n\n#### Complete Custom Configuration\n\n```java\nfinal Resilience4jConfiguration resilience4jConfig = Resilience4jConfiguration.builder()\n        .withRetry(RetryConfig.custom()\n                .maxAttempts(3)\n                .waitDuration(Duration.ofMillis(500))\n                .retryOnException(throwable -\u003e \n                    throwable instanceof CheckoutApiException \u0026\u0026\n                    ((CheckoutApiException) throwable).getHttpStatusCode() \u003e= 500)\n                .build())\n        // Deactivated by default\n        //.withRateLimiter(RateLimiterConfig.custom()           \n        //        .limitForPeriod(100)\n        //        .limitRefreshPeriod(Duration.ofSeconds(1))\n        //        .timeoutDuration(Duration.ofSeconds(5))\n        //        .build())\n        // Deactivated by default\n        //.withCircuitBreaker(CircuitBreakerConfig.custom()\n        //        .failureRateThreshold(50)\n        //        .waitDurationInOpenState(Duration.ofSeconds(30))\n        //        .slidingWindowSize(10)\n        //        .build())\n        .build();\n\nfinal CheckoutApi checkoutApi = CheckoutSdk.builder()\n        .staticKeys()\n        .secretKey(\"secret_key\")\n        .environment(Environment.PRODUCTION)\n        .synchronous(true)\n        .resilience4jConfiguration(resilience4jConfig)\n        .build();\n```\n\n**Important Notes:**\n- Resilience4j configuration only works with **synchronous** mode (`synchronous(true)`)\n- For asynchronous operations, implement your own retry logic using CompletableFuture patterns\n- All resilience patterns are optional - configure only what you need\n- Rate limiter helps respect API rate limits and prevent overwhelming the service\n\n## Code of Conduct\n\nPlease refer to [Code of Conduct](CODE_OF_CONDUCT.md)\n\n## Licensing\n\n[MIT](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheckout%2Fcheckout-sdk-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcheckout%2Fcheckout-sdk-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheckout%2Fcheckout-sdk-java/lists"}