### KSeF Client Certificate and Key Setup
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Configure certificates and private keys required for authentication. This setup is crucial for signing authentication requests.
```java
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.io.FileInputStream;
// Register cryptography provider
Security.addProvider(new BouncyCastleProvider());
// Load certificate and private key
KeyStore keystore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream("path/to/certificate.p12")) {
keystore.load(fis, "password".toCharArray());
}
// Extract certificate and key
Certificate cert = keystore.getCertificate("certificate_alias");
PrivateKey privateKey = (PrivateKey) keystore.getKey(
"certificate_alias",
"password".toCharArray()
);
// Use with client for signing authentication requests
// See authentication.md for signing examples
```
--------------------------------
### Get Authentication Challenge
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Initializes the authentication mechanism by requesting a challenge from the KSeF server. This is the first step in the authentication process.
```java
AuthenticationChallengeResponse getAuthChallenge() throws ApiException;
```
```java
try {
AuthenticationChallengeResponse challenge = client.getAuthChallenge();
// Use challenge data to create signed request
} catch (ApiException e) {
System.err.println("Error: " + e.getMessage());
}
```
--------------------------------
### Get Certificate Enrollment Info
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get data required to prepare a certificate enrollment request. Requires an access token for authentication.
```java
CertificateEnrollmentsInfoResponse getCertificateEnrollmentInfo(
String accessToken
) throws ApiException;
```
--------------------------------
### Complete Authentication Workflow Example
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Demonstrates the full authentication process, from obtaining a challenge to making an authenticated API call. Requires a PKCS12 certificate file and password.
```java
import pl.akmf.ksef.sdk.client.interfaces.KSeFClient;
import pl.akmf.ksef.sdk.api.services.DefaultCryptographyService;
import pl.akmf.ksef.sdk.client.interfaces.CryptographyService;
import java.security.*;
import java.util.Base64;
public class FullAuthenticationExample {
public static void main(String[] args) throws Exception {
KSeFClient client = new DefaultKsefClient();
CryptographyService crypto = new DefaultCryptographyService();
// Step 1: Get authentication challenge
System.out.println("Step 1: Getting authentication challenge...");
AuthenticationChallengeResponse challenge = client.getAuthChallenge();
String challengeValue = challenge.getChallenge();
String contextId = challenge.getContextIdentifier();
System.out.println("Challenge: " + challengeValue);
// Step 2: Load certificate for signing
System.out.println("Step 2: Loading certificate...");
KeyStore keystore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream("certificate.p12")) {
keystore.load(fis, "password".toCharArray());
}
PrivateKey privateKey = (PrivateKey) keystore.getKey(
"certificate_alias",
"password".toCharArray()
);
X509Certificate certificate =
(X509Certificate) keystore.getCertificate("certificate_alias");
// Step 3: Create authentication request XML
System.out.println("Step 3: Creating authentication request...");
String authXml = new AuthTokenRequestBuilder()
.withChallenge(challengeValue)
.withContextIdentifier(contextId)
.withIdentifier("12345678901") // NIP
.withIdentifierType("ORGANIZATION")
.build();
System.out.println("Auth XML created");
// Step 4: Sign the request
System.out.println("Step 4: Signing request...");
byte[] xmlBytes = authXml.getBytes(StandardCharsets.UTF_8);
byte[] signature = crypto.signWithCertificate(
privateKey,
xmlBytes,
"SHA256withRSA"
);
System.out.println("Signature generated, size: " + signature.length);
// Step 5: Create XAdES signature structure (simplified)
// In production, use proper XAdES library
String signedXml = wrapInXAdESSignature(authXml, signature);
// Step 6: Submit signed request
System.out.println("Step 5: Submitting signed request...");
SignatureResponse signResponse = client.submitAuthTokenRequest(
signedXml,
true // verifyCertificateChain
);
String authToken = signResponse.getSessionToken();
String refNumber = signResponse.getReferenceNumber();
System.out.println("Request submitted, reference: " + refNumber);
// Step 7: Poll authentication status
System.out.println("Step 6: Checking authentication status...");
AuthStatus authStatus = null;
for (int i = 0; i < 30; i++) {
authStatus = client.getAuthStatus(refNumber, authToken);
if (!"PENDING".equals(authStatus.getStatus())) {
break;
}
System.out.println(" Status: PENDING, waiting...");
Thread.sleep(1000);
}
System.out.println("Final status: " + authStatus.getStatus());
// Step 8: Redeem authentication token
System.out.println("Step 7: Redeeming token...");
AuthOperationStatusResponse authOpStatus = client.redeemToken(
authStatus.getAuthToken()
);
String accessToken = authOpStatus.getAccessToken();
String refreshToken = authOpStatus.getRefreshToken();
System.out.println("Tokens obtained, access token valid for: " +
authOpStatus.getExpiresIn() + " seconds");
// Step 9: Now you can use accessToken for API calls
System.out.println("Step 8: Making authenticated API call...");
GetRateLimitResponse rateLimit = client.getRateLimit(accessToken);
System.out.println("Rate limit: " + rateLimit.getRequestLimit() +
" requests per window");
System.out.println("\nAuthentication workflow completed successfully!");
}
private static String wrapInXAdESSignature(String xmlContent, byte[] signature) {
// Simplified - in production use XAdES library
String sigBase64 = Base64.getEncoder().encodeToString(signature);
return "" +
"" +
"" + xmlContent + "" +
"" + sigBase64 + "" +
"";
}
}
```
--------------------------------
### Complete Session Encryption Workflow
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
This example demonstrates the full process of encrypting invoice data for transmission via KSeF. It includes generating a session key, encrypting it with the KSeF public key, opening an online session, encrypting the invoice, calculating its hash, and sending the encrypted invoice.
```java
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.SecureRandom;
import java.util.Base64;
public class SessionEncryptionExample {
public static void main(String[] args) throws Exception {
KSeFClient client = new DefaultKsefClient();
CryptographyService crypto = new DefaultCryptographyService();
// Step 1: Get KSeF public key for encrypting session key
System.out.println("Step 1: Getting KSeF public key...");
List pubKeys = client.retrievePublicKeyCertificate();
byte[] ksefPublicKeyDer = Base64.getDecoder().decode(
pubKeys.get(0).getCertificate()
);
// Step 2: Generate AES-256 session key
System.out.println("Step 2: Generating session key...");
SecretKey sessionKey = crypto.generateAESSessionKey(256);
// Step 3: Generate random IV for CBC mode
System.out.println("Step 3: Generating IV...");
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
String ivBase64 = Base64.getEncoder().encodeToString(iv);
// Step 4: Encrypt session key with KSeF public key
System.out.println("Step 4: Encrypting session key...");
byte[] sessionKeyBytes = sessionKey.getEncoded();
byte[] encryptedSessionKey = crypto.encryptRSA(
ksefPublicKeyDer,
sessionKeyBytes
);
String encryptedSessionKeyBase64 = Base64.getEncoder().encodeToString(
encryptedSessionKey
);
// Step 5: Open online session with encrypted key
System.out.println("Step 5: Opening online session...");
OpenOnlineSessionRequest sessionRequest =
new OpenOnlineSessionRequestBuilder()
.withEncryptionAlgorithm("RSA2048_AES256_CBC")
.withEncryptedSessionKey(encryptedSessionKeyBase64)
.withIv(ivBase64)
.build();
OpenOnlineSessionResponse sessionResponse = client.openOnlineSession(
sessionRequest,
UpoVersion.UPO_V4_3,
accessToken
);
System.out.println("Session opened: " + sessionResponse.getReferenceNumber());
// Step 6: Encrypt invoice data
System.out.println("Step 6: Encrypting invoice...");
String invoiceXml = "......";
byte[] invoiceBytes = invoiceXml.getBytes(StandardCharsets.UTF_8);
byte[] encryptedInvoice = crypto.encryptAES(
sessionKey,
iv,
invoiceBytes
);
String encryptedInvoiceBase64 = Base64.getEncoder().encodeToString(
encryptedInvoice
);
// Step 7: Calculate hash of original invoice
System.out.println("Step 7: Calculating invoice hash...");
String invoiceHash = crypto.hashSHA256(invoiceBytes);
// Step 8: Send encrypted invoice
System.out.println("Step 8: Sending encrypted invoice...");
SendInvoiceOnlineSessionRequest invoiceRequest =
new SendInvoiceOnlineSessionRequest();
invoiceRequest.setEncryptedInvoice(encryptedInvoiceBase64);
invoiceRequest.setHashValue(Base64.getEncoder().encodeToString(
invoiceHash.getBytes()
));
invoiceRequest.setEncryptedFileName(Base64.getEncoder().encodeToString(
"invoice.xml".getBytes()
));
SendInvoiceResponse response = client.onlineSessionSendInvoice(
sessionResponse.getReferenceNumber(),
invoiceRequest,
accessToken
);
System.out.println("Invoice sent!");
System.out.println("KSeF number: " + response.getKsefNumber());
System.out.println("Status: " + response.getProcessingCode());
}
}
```
--------------------------------
### KSeFClient Public Methods
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/MANIFEST.md
The KSeFClient interface provides over 50 public methods for interacting with the KSeF system. These methods cover session management, invoice operations, certificate management, authentication, permissions, and more. Each method includes its full signature, parameter details, return types, exceptions, and code examples.
```APIDOC
## KSeFClient Interface
### Description
Provides a comprehensive set of public methods for interacting with the KSeF system, covering session management, invoice operations, certificate management, authentication, permissions, and more.
### Methods
- **Session Management (Batch):** 4 methods
- **Session Management (Online):** 3 methods
- **Session Queries:** 2 methods
- **Session Invoices:** 3 methods
- **UPO Operations:** 3 methods
- **Invoice Queries:** 4 methods
- **Certificate Operations:** 7 methods
- **Authentication & Authorization:** 6 methods
- **Permissions Management:** 8 methods
- **Permission Revocation:** 2 methods
- **Permission Queries:** 7 methods
- **Session Management (Auth):** 3 methods
- **Limits & Rate Control:** 4 methods
- **Public Keys:** 1 method
- **Peppol Providers:** 1 method
- **Test Data Management:** 12 methods
### Parameters
Each method includes a detailed parameters table with name, type, required status, default value, and description.
### Return Type
Documentation for the return type of each method.
### Exceptions
Details on exceptions thrown by each method, including conditions.
### Code Example
Practical code examples demonstrating the usage of each method.
### Source File Reference
Reference to the source file where the method is defined.
```
--------------------------------
### Get Certificate Metadata List
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Query certificates with search criteria and pagination. Requires search criteria, page size, page offset, and an access token.
```java
CertificateMetadataListResponse getCertificateMetadataList(
QueryCertificatesRequest body,
int pageSize,
int pageOffset,
String accessToken
) throws ApiException;
```
--------------------------------
### Get Active Sessions with Pagination
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves a paginated list of active authentication sessions. Requires an access token.
```java
AuthenticationListResponse getActiveSessions(
Integer pageSize,
String continuationToken,
String accessToken
) throws ApiException;
```
--------------------------------
### RSA Encryption Example
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Encrypts data using RSA with a provided public key. This is typically used to encrypt a symmetric session key before transmitting it.
```java
CryptographyService crypto = new DefaultCryptographyService();
// Get KSeF public key certificate
List certs = client.retrievePublicKeyCertificate();
PublicKeyCertificate ksefPublicKeyData = certs.get(0);
byte[] publicKeyBytes = Base64.getDecoder().decode(
ksefPublicKeyData.getCertificate()
);
// Encrypt AES session key with KSeF's public key
byte[] sessionKeyBytes = /* 32 bytes for AES-256 */;
byte[] encryptedSessionKey = crypto.encryptRSA(
publicKeyBytes,
sessionKeyBytes
);
String encryptedKeyBase64 = Base64.getEncoder().encodeToString(
encryptedSessionKey
);
```
--------------------------------
### Error Handling
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/MANIFEST.md
A comprehensive guide to error handling, detailing the exception hierarchy, 7 specific exception classes (e.g., ApiException, KsefApiException), HTTP status code mapping, and common error scenarios with recovery strategies.
```APIDOC
## Error Handling Guide
### Description
Provides a detailed overview of the exception hierarchy, specific exception classes, HTTP status code mapping, and strategies for handling common errors.
### Exception Hierarchy
Details on the inheritance structure of exceptions.
### Exception Classes
- **ApiException:** Base class
- **KsefApiException:** Domain errors
- **BadRequestApiException:** HTTP 400
- **UnauthorizedApiException:** HTTP 401
- **ForbiddenApiException:** HTTP 403
- **TooManyRequestsApiException:** HTTP 429
- **GoneApiException:** HTTP 410
### HTTP Status Code Mapping
Detailed mapping between HTTP status codes and corresponding exceptions.
### Error Structures
Documentation for `ExceptionResponse` and `ErrorDetail` structures.
### Common Error Scenarios
1. Session not found
2. Invalid invoice encryption
3. Token expired
4. Permission denied
5. Concurrent modification
6. Rate limit exceeded
### Recovery Strategies
Strategies for recovering from common error scenarios, including retry logic with exponential backoff.
### Best Practices
Patterns for effective exception handling, such as specific exception handling and error code dispatch.
```
--------------------------------
### Handle Session Not Found (404)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/errors.md
Catch KsefApiException with code 404 to handle cases where a session reference number is invalid or has been deleted. This example shows how to verify the reference number and potentially list existing sessions.
```java
try {
client.getSessionStatus(refNumber, accessToken);
} catch (KsefApiException e) {
if (e.getCode() == 404) {
// Verify reference number is correct
System.err.println("Session " + refNumber + " not found");
// May need to list sessions to find correct one
SessionsQueryResponse sessions = client.getSessions(
new SessionsQueryRequest(), 10, null, accessToken
);
}
}
```
--------------------------------
### Get Peppol Providers List
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves a paginated list of registered Peppol service providers. Default values are provided for page offset and size.
```java
PeppolProvidersListResponse getPeppolProvidersList(
int pageOffset,
int pageSize
) throws ApiException;
```
--------------------------------
### Submit Invoice via Online Session
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Guides through the process of submitting an invoice using an online session. This involves opening a session, sending the invoice, and then closing the session.
```java
// 1. Open online session
OpenOnlineSessionResponse sessionResp = client.openOnlineSession(
sessionRequest,
UpoVersion.UPO_V4_3,
accessToken
);
// 2. Send invoice
SendInvoiceResponse invoiceResp = client.onlineSessionSendInvoice(
sessionResp.getReferenceNumber(),
encryptedInvoiceRequest,
accessToken
);
// 3. Close session
client.closeOnlineSession(
sessionResp.getReferenceNumber(),
accessToken
);
```
--------------------------------
### KSeF Client Initialization (DEMO Environment)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Initialize the client for the DEMO environment. Remember to use demo credentials and test data for testing purposes.
```java
import pl.akmf.ksef.sdk.api.DefaultKsefClient;
// DEMO environment: https://demo.ksef.mf.gov.pl
KSeFClient client = new DefaultKsefClient();
// Note: Use demo credentials and test data
// Test subjects/persons can be created with:
// client.createTestSubject(...);
// client.createTestPerson(...);
```
--------------------------------
### Initialize KSeF Client
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Instantiate the KSeF client using the default configuration. This is the first step before performing any operations.
```java
import pl.akmf.ksef.sdk.api.DefaultKsefClient;
import pl.akmf.ksef.sdk.client.interfaces.KSeFClient;
// Create client with default configuration
KSeFClient client = new DefaultKsefClient();
```
--------------------------------
### getCertificateEnrollmentInfo
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get data required to prepare a certificate enrollment request.
```APIDOC
## getCertificateEnrollmentInfo()
### Description
Get data required to prepare a certificate enrollment request.
### Method
Not specified (likely a SDK method call)
### Endpoint
Not specified
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```java
CertificateEnrollmentsInfoResponse response = ksefClient.getCertificateEnrollmentInfo(accessToken);
```
### Response
#### Success Response
- **CertificateEnrollmentsInfoResponse** - Required enrollment data
```
--------------------------------
### getSubjectCertificateLimit
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get certificate limits for the current subject. Requires an access token.
```APIDOC
## getSubjectCertificateLimit
### Description
Get certificate limits for the current subject.
### Method
```java
GetSubjectLimitResponse getSubjectCertificateLimit(String accessToken)
```
### Parameters
#### Header Parameters
- **accessToken** (String) - Required - Authentication access token.
### Returns
`GetSubjectLimitResponse` - Current certificate limits
```
--------------------------------
### Get Certificate Expiry Date
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Retrieves the expiry date of an X.509 certificate.
```java
Date getCertificateExpiryDate(X509Certificate cert);
```
--------------------------------
### Import Main Client Interface
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Import the main KSeF client interface and its default implementation.
```java
import pl.akmf.ksef.sdk.client.interfaces.KSeFClient;
import pl.akmf.ksef.sdk.api.DefaultKsefClient;
```
--------------------------------
### getContextSessionLimit
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get session operation limits for the current context. Requires an access token.
```APIDOC
## getContextSessionLimit
### Description
Get session operation limits for the current context.
### Method
```java
GetContextLimitResponse getContextSessionLimit(String accessToken)
```
### Parameters
#### Header Parameters
- **accessToken** (String) - Required - Authentication access token.
### Returns
`GetContextLimitResponse` - Current session limits
```
--------------------------------
### Demo Environment Configuration
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Use this configuration for the demo environment. It enables test data operations and has lower rate limits.
```yaml
sdk:
config:
base-uri: https://demo.ksef.mf.gov.pl
environment: DEMO
# Demo allows test data operations
test-data-enabled: true
```
--------------------------------
### getRateLimit
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get API request rate limits for the current context. Requires an access token.
```APIDOC
## getRateLimit
### Description
Get API request rate limits for the current context.
### Method
```java
GetRateLimitResponse getRateLimit(String accessToken)
```
### Parameters
#### Header Parameters
- **accessToken** (String) - Required - Authentication access token.
### Returns
`GetRateLimitResponse` - Current rate limit values
```
--------------------------------
### Open Batch Session with KSeFClient
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Use this method to initiate a batch session for sending multiple invoices. Configure the request body with invoice details and specify the UPO version. Requires an access token for authentication.
```java
OpenBatchSessionRequest request = new OpenBatchSessionRequest();
// ... configure request ...
try {
OpenBatchSessionResponse response = client.openBatchSession(
request,
UpoVersion.UPO_V4_3,
accessToken
);
String referenceNumber = response.getReferenceNumber();
System.out.println("Batch session opened: " + referenceNumber);
} catch (ApiException e) {
System.err.println("Failed to open batch session: " + e.getMessage());
}
```
--------------------------------
### Get Subject Certificate Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the certificate limits for the current subject. Requires an access token.
```java
GetSubjectLimitResponse getSubjectCertificateLimit(String accessToken) throws ApiException;
```
--------------------------------
### Get Certificate Subject Distinguished Name
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Extracts the Subject Distinguished Name (DN) from an X.509 certificate.
```java
String getCertificateSubjectDN(X509Certificate cert);
```
--------------------------------
### Build Authentication Token Request (Java)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Constructs XML-formatted authentication requests for signing and submission to KSeF. Use this builder to initialize a session by providing challenge, context identifier, and organization identifier.
```java
import pl.akmf.ksef.sdk.api.builders.auth.AuthTokenRequestBuilder;
String xmlRequest = new AuthTokenRequestBuilder()
.withChallenge(challengeResponse.getChallenge())
.withContextIdentifier(challengeResponse.getContextIdentifier())
.withIdentifier("12345678901") // NIP
.withIdentifierType("ORGANIZATION")
.build();
// xmlRequest is now ready to be signed with certificate
SignatureResponse response = client.submitAuthTokenRequest(
signedXmlRequest,
true
);
```
--------------------------------
### Get Session Operation Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the session operation limits for the current context. Requires an access token.
```java
GetContextLimitResponse getContextSessionLimit(String accessToken) throws ApiException;
```
--------------------------------
### Open Online Session with KSeFClient
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Initializes an interactive session for sending invoices one at a time. Requires request body, UPO version, and an access token. Handles potential API exceptions.
```java
OpenOnlineSessionResponse openOnlineSession(
OpenOnlineSessionRequest body,
UpoVersion upoVersion,
String accessToken
) throws ApiException;
```
```java
OpenOnlineSessionRequest request = new OpenOnlineSessionRequest();
// ... configure request ...
try {
OpenOnlineSessionResponse response = client.openOnlineSession(
request,
UpoVersion.UPO_V4_3,
accessToken
);
System.out.println("Online session opened: " + response.getReferenceNumber());
} catch (ApiException e) {
System.err.println("Error: " + e.getMessage());
}
```
--------------------------------
### Retrieve Default Headers
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get a copy of the default HTTP headers configured for the client. These headers can be set in application.yaml.
```java
Map getDefaultHeaders();
```
```java
KSeFClient client = new DefaultKsefClient(/* ... */);
Map headers = client.getDefaultHeaders();
headers.forEach((key, value) -> System.out.println(key + ": " + value));
```
--------------------------------
### getAuthChallenge
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Initializes the authentication process by requesting a challenge from the KSeF server. This is the first step in the authentication flow.
```APIDOC
## getAuthChallenge()
### Description
Initialize the authentication mechanism by requesting a challenge.
### Method
```java
AuthenticationChallengeResponse getAuthChallenge() throws ApiException;
```
### Parameters
No parameters required.
### Returns
`AuthenticationChallengeResponse` - Challenge data for signing.
### Example
```java
try {
AuthenticationChallengeResponse challenge = client.getAuthChallenge();
// Use challenge data to create signed request
} catch (ApiException e) {
System.err.println("Error: " + e.getMessage());
}
```
```
--------------------------------
### Get Authentication Status
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Checks the status of an ongoing authentication operation using a reference number and a temporary authentication token.
```java
AuthStatus getAuthStatus(
String referenceNumber,
String authenticationToken
) throws ApiException;
```
--------------------------------
### Import KSeFClient Interface
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Import the primary interface for interacting with the KSeF system.
```java
import pl.akmf.ksef.sdk.client.interfaces.KSeFClient;
```
--------------------------------
### KSeF Authentication Flow
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Demonstrates the complete authentication process, including obtaining a challenge, signing with a certificate, polling for status, and redeeming a token to obtain an access token.
```java
// 1. Get challenge
AuthenticationChallengeResponse challenge = client.getAuthChallenge();
// 2. Sign with certificate
SignatureResponse signed = client.submitAuthTokenRequest(
signedXml,
true // verifyCertificateChain
);
// 3. Poll status
AuthStatus status = client.getAuthStatus(
signed.getReferenceNumber(),
signed.getSessionToken()
);
// 4. Redeem token
AuthOperationStatusResponse tokens = client.redeemToken(
status.getAuthToken()
);
String accessToken = tokens.getAccessToken();
```
--------------------------------
### Get Certificate Enrollment Status
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Check the status of a certificate enrollment request using its reference number and an access token.
```java
CertificateEnrollmentStatusResponse getCertificateEnrollmentStatus(
String referenceNumber,
String accessToken
) throws ApiException;
```
--------------------------------
### Build Open Batch Session Request
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Use this builder to construct requests for initializing batch invoice submission sessions. This includes providing the invoice hash, encryption details, and session key.
```java
import pl.akmf.ksef.sdk.api.builders.batch.OpenBatchSessionRequestBuilder;
OpenBatchSessionRequest request =
new OpenBatchSessionRequestBuilder()
.withInvoiceHash(sha256HashOfAllInvoices)
.withEncryptionAlgorithm("RSA2048_AES256_CBC")
.withEncryptedSessionKey(encryptedKeyBase64)
.withIv(ivBase64)
.build();
OpenBatchSessionResponse response = client.openBatchSession(
request,
UpoVersion.UPO_V4_3,
accessToken
);
```
--------------------------------
### Async Invoice Queries with KSeF Client
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Implement asynchronous invoice queries for bulk exports. Initiates a query, polls for status, and downloads results. Includes error handling and a polling delay.
```java
// Initiate async operation
InitAsyncInvoicesQueryResponse initResponse =
client.initAsyncQueryInvoice(exportRequest, accessToken);
String referenceNumber = initResponse.getReferenceNumber();
// Poll status periodically
while (true) {
InvoiceExportStatus status =
client.checkStatusAsyncQueryInvoice(referenceNumber, accessToken);
if ("FINISHED".equals(status.getStatus())) {
// Download result packages
status.getAvailableParts().forEach(part -> {
byte[] packageData = client.downloadPackagePart(part);
// Decrypt and process...
});
break;
} else if ("FAILED".equals(status.getStatus())) {
throw new Exception("Export failed");
}
Thread.sleep(5000); // Wait 5 seconds before retrying
}
```
--------------------------------
### getSessionInvoiceStatus
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Get detailed status of a specific invoice within a session. This allows for granular tracking of individual invoice processing.
```APIDOC
## getSessionInvoiceStatus()
### Description
Get detailed status of a specific invoice in a session.
### Method Signature
`SessionInvoiceStatusResponse getSessionInvoiceStatus(String referenceNumber, String invoiceReferenceNumber, String accessToken)`
### Parameters
#### Path Parameters
- None
#### Query Parameters
- None
#### Request Body
- None
#### Method Parameters
- **referenceNumber** (String) - Required - Session reference number
- **invoiceReferenceNumber** (String) - Required - Invoice reference number within session
- **accessToken** (String) - Required - Authentication access token
### Returns
- **SessionInvoiceStatusResponse** - Detailed invoice status
### Throws
- **ApiException**
```
--------------------------------
### Get API Request Rate Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the API request rate limits for the current context. Requires an access token.
```java
GetRateLimitResponse getRateLimit(String accessToken) throws ApiException;
```
--------------------------------
### Import Cryptography Services
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Import the default cryptography service implementation and its interface.
```java
import pl.akmf.ksef.sdk.api.services.DefaultCryptographyService;
import pl.akmf.ksef.sdk.client.interfaces.CryptographyService;
```
--------------------------------
### Add ksef-client Dependency with Gradle
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Include the ksef-client library in your project using Gradle. Ensure you configure the GitHub Packages repository for access.
```gradle
dependencies {
implementation("pl.akmf.ksef-sdk:ksef-client:3.0.26")
}
```
```gradle
repositories {
maven {
url = uri("https://maven.pkg.github.com/CIRFMF/ksef-client-java")
credentials {
username = System.getenv("GITHUB_ACTOR") ?: "your_username"
password = System.getenv("GITHUB_TOKEN") ?: "your_github_token"
}
}
}
```
--------------------------------
### Get Certificate Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Retrieves the current certificate limits, including the maximum number of certificates, used certificates, and remaining limit.
```java
GetSubjectLimitResponse limits = client.getSubjectCertificateLimit(accessToken);
System.out.println("Max certificates: " + limits.getCertificateLimit());
System.out.println("Used: " + limits.getCertificatesUsed());
System.out.println("Remaining: " + limits.getRemainingLimit());
```
--------------------------------
### Logback Configuration for KSeF Client
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Configure Logback to manage logging levels for the KSeF client, HTTP client, and crypto operations. Sets the root logger to INFO and appends to the console.
```xml
%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
```
--------------------------------
### initAsyncQueryInvoice
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/types.md
Initiates an asynchronous invoice export or query. This method starts a background process for retrieving invoice data over a specified range.
```APIDOC
## initAsyncQueryInvoice
### Description
Initiates an asynchronous invoice export or query operation. This is used for retrieving invoice data over a specified date range.
### Method
POST (assumed based on operation)
### Endpoint
/invoices/export/async/init (assumed based on operation)
### Parameters
#### Request Body
- **rangeStartDate** (String) - Yes - Start date for invoice range
- **rangeEndDate** (String) - Yes - End date for invoice range
- **encryptionAlgorithm** (String) - Yes - Encryption algorithm for results
- **encryptedSessionKey** (String) - Yes - Encrypted key (Base64)
- **iv** (String) - Yes - Initialization vector (Base64)
### Response
#### Success Response (200)
- **referenceNumber** (String) - Operation reference for status checks
- **processingStartTimestamp** (String) - When processing started
```
--------------------------------
### Configure JVM Proxy Settings
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Set these JVM properties to configure HTTP or HTTPS proxy settings. Use http.nonProxyHosts to exclude specific hosts from proxying.
```bash
# HTTP proxy
-Dhttp.proxyHost=proxy.example.com
-Dhttp.proxyPort=8080
-Dhttp.proxyUser=username
-Dhttp.proxyPassword=password
# HTTPS proxy
-Dhttps.proxyHost=proxy.example.com
-Dhttps.proxyPort=8080
-Dhttps.proxyUser=username
-Dhttps.proxyPassword=password
# No proxy for specific hosts
-Dhttp.nonProxyHosts=localhost|*.internal.example.com
```
--------------------------------
### Get KSeF Token Details
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Fetches detailed information for a specific KSeF token using its reference number. Requires an access token.
```java
AuthenticationToken getKsefToken(
String referenceNumber,
String accessToken
) throws ApiException;
```
--------------------------------
### Import Builders
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Import builder classes for constructing various KSeF requests and objects.
```java
import pl.akmf.ksef.sdk.api.builders.auth.*;
import pl.akmf.ksef.sdk.api.builders.batch.*;
import pl.akmf.ksef.sdk.api.builders.certificate.*;
import pl.akmf.ksef.sdk.api.builders.invoices.*;
import pl.akmf.ksef.sdk.api.builders.permission.*;
import pl.akmf.ksef.sdk.api.builders.session.*;
```
--------------------------------
### Get Current Session Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Retrieves the current session limits, including the maximum number of invoices, used invoices, and remaining limit.
```java
GetContextLimitResponse limits = client.getContextSessionLimit(accessToken);
System.out.println("Max invoices: " + limits.getInvoiceLimit());
System.out.println("Used: " + limits.getInvoicesUsed());
System.out.println("Remaining: " + limits.getRemainingLimit());
```
--------------------------------
### CertificateBuilders Facade Methods
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Provides static factory methods for creating certificate builders. These methods initiate the builder pattern for various certificate-related operations.
```APIDOC
## CertificateBuilders Facade
Provides static factory methods for all certificate builders.
**Full Name:** `pl.akmf.ksef.sdk.api.builders.certificate.CertificateBuilders`
**Static Methods:**
- `sendEnrollment()`: Returns a `SendCertificateEnrollmentRequestBuilder`.
- `metadataList()`: Returns a `CertificateMetadataListRequestBuilder`.
- `revoke()`: Returns a `CertificateRevokeRequestBuilder`.
### Example Usage
```java
import pl.akmf.ksef.sdk.api.builders.certificate.CertificateBuilders;
SendCertificateEnrollmentRequest request = CertificateBuilders.sendEnrollment()
.withCommonName("API Client")
.withOrganizationName("Company")
.withCsr(csrData)
.build();
```
```
--------------------------------
### Get Certificate List
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieve certificates by serial numbers in Base64-encoded DER format. Requires a request body with serial numbers and an access token.
```java
CertificateListResponse getCertificateList(
CertificateListRequest body,
String accessToken
) throws ApiException;
```
--------------------------------
### Certificate Loading
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Loads X.509 certificates from PEM-encoded data.
```APIDOC
## loadCertificate
### Description
Loads a single X.509 certificate from PEM-encoded data.
### Method Signature
`X509Certificate loadCertificate(String pemData)`
### Parameters
#### Path Parameters
- **pemData** (String) - Required - PEM-encoded certificate data
### Returns
- **X509Certificate** - The loaded certificate
## loadCertificateChain
### Description
Loads an array of X.509 certificates (a certificate chain) from PEM-encoded data.
### Method Signature
`X509Certificate[] loadCertificateChain(String pemData)`
### Parameters
#### Path Parameters
- **pemData** (String) - Required - PEM-encoded certificate chain data
### Returns
- **X509Certificate[]** - An array of loaded certificates representing the chain
```
--------------------------------
### InitAsyncInvoicesQueryResponse Java Class
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/types.md
Response received after initiating an asynchronous invoice query. Provides a reference number for status checks and the processing start timestamp.
```java
public class InitAsyncInvoicesQueryResponse {
private String referenceNumber;
private String processingStartTimestamp;
}
```
--------------------------------
### Import Models and Types
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/README.md
Import various model and type classes used within the KSeF client SDK.
```java
import pl.akmf.ksef.sdk.client.model.*;
import pl.akmf.ksef.sdk.client.model.auth.*;
import pl.akmf.ksef.sdk.client.model.certificate.*;
import pl.akmf.ksef.sdk.client.model.invoice.*;
import pl.akmf.ksef.sdk.client.model.permission.*;
import pl.akmf.ksef.sdk.client.model.session.*;
```
--------------------------------
### Build Open Online Session Request
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Use this builder to construct requests for initializing interactive invoice submission sessions. Ensure encryption parameters like algorithm, session key, and IV are properly encoded.
```java
import pl.akmf.ksef.sdk.api.builders.session.OpenOnlineSessionRequestBuilder;
import java.util.Base64;
String encryptedKeyBase64 = Base64.getEncoder().encodeToString(encryptedKey);
String ivBase64 = Base64.getEncoder().encodeToString(iv);
OpenOnlineSessionRequest request =
new OpenOnlineSessionRequestBuilder()
.withEncryptionAlgorithm("RSA2048_AES256_CBC")
.withEncryptedSessionKey(encryptedKeyBase64)
.withIv(ivBase64)
.build();
OpenOnlineSessionResponse response = client.openOnlineSession(
request,
UpoVersion.UPO_V4_3,
accessToken
);
```
--------------------------------
### Send Certificate Enrollment Request Builder
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Use this builder to initiate the enrollment process for a certificate. Requires common name, organization name, and CSR data.
```java
import pl.akmf.ksef.sdk.api.builders.certificate.CertificateBuilders;
SendCertificateEnrollmentRequest request = CertificateBuilders.sendEnrollment()
.withCommonName("API Client")
.withOrganizationName("Company")
.withCsr(csrData)
.build();
```
--------------------------------
### Get KSeF Session Status
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the status of a specific invoicing session using its reference number and an access token. Handles potential API exceptions.
```java
SessionStatusResponse getSessionStatus(
String referenceNumber,
String accessToken
) throws ApiException;
```
```java
try {
SessionStatusResponse status = client.getSessionStatus(refNumber, accessToken);
System.out.println("Session status: " + status.getSessionStatus());
} catch (ApiException e) {
System.err.println("Error: " + e.getMessage());
}
```
--------------------------------
### Get Current Default Headers from KSeF Client
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Retrieve all currently set default headers using `getDefaultHeaders`. The returned map can be iterated to view or process the headers.
```java
Map headers = client.getDefaultHeaders();
headers.forEach((key, value) ->
System.out.println(key + ": " + value)
);
```
--------------------------------
### Add ksef-client Dependency with Maven
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Integrate the ksef-client library into your Maven project. Configure your Maven settings to access the GitHub Packages repository.
```xml
pl.akmf.ksef-sdk
ksef-client
3.0.26
```
```xml
github
your_username
your_github_token
github
https://maven.pkg.github.com/CIRFMF/ksef-client-java
```
--------------------------------
### RSA Decryption Example
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Decrypts data using RSA with a provided private key. This is used to decrypt sensitive information received from a service, such as an encrypted session key.
```java
// Load private key from PKCS12 keystore
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream("cert.p12"), "password".toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey(
"certificate_alias",
"password".toCharArray()
);
CryptographyService crypto = new DefaultCryptographyService();
// Decrypt data from KSeF response
byte[] decryptedData = crypto.decryptRSA(
privateKey,
encryptedResponseData
);
```
--------------------------------
### Generate QR Code as Base64
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Generates a QR code as a Base64 encoded string for the given content at the specified size.
```java
String generateQrCodeAsBase64(String content, int size);
```
--------------------------------
### Download Session UPO (Java)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the aggregated UPO for a given session. Requires session reference number, UPO reference number, and an access token. Returns the UPO as an XML byte array.
```java
byte[] getSessionUpo(
String referenceNumber,
String upoReferenceNumber,
String accessToken
) throws ApiException;
```
--------------------------------
### Handle Permission Denied on Grant
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/errors.md
Catch ForbiddenApiException when attempting to grant permissions without the necessary privileges. This example shows how to log the error and verify current permissions.
```java
try {
client.grantsPermissionEntity(grantRequest, accessToken);
} catch (ForbiddenApiException e) {
System.err.println("Cannot grant permissions");
// Only subjects with CredentialsManage can grant
// Request from parent entity or administrator
// Verify current permissions
QueryPersonalGrantResponse grants =
client.searchPersonalGrantPermission(
new QueryPersonalGrantRequest(),
0, 100, accessToken
);
grants.getEntries().forEach(entry ->
System.out.println("Has: " + entry.getPermissionType())
);
}
```
--------------------------------
### Configure Trust Store for SSL/TLS
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Set JVM properties to specify a custom trust store for SSL/TLS certificate validation. Ensure the `trustStorePassword` and `trustStoreType` are correctly set for your keystore.
```bash
# Use custom truststore
-Djavax.net.ssl.trustStore=/path/to/truststore.jks
-Djavax.net.ssl.trustStorePassword=password
-Djavax.net.ssl.trustStoreType=JKS
# For PKCS12 truststore
-Djavax.net.ssl.trustStoreType=PKCS12
```
--------------------------------
### Initiate Asynchronous Invoice Export
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Initiate an asynchronous bulk invoice export operation. Requires an access token for authentication and an InvoiceExportRequest object specifying filters and encryption settings.
```java
InitAsyncInvoicesQueryResponse initAsyncQueryInvoice(
InvoiceExportRequest request,
String accessToken
) throws ApiException;
```
--------------------------------
### Get Session Invoice Status
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/KSeFClient.md
Retrieves the detailed status of a specific invoice within a session. Requires session reference number, invoice reference number, and access token.
```java
SessionInvoiceStatusResponse getSessionInvoiceStatus(
String referenceNumber,
String invoiceReferenceNumber,
String accessToken
) throws ApiException;
```
--------------------------------
### AES Encryption Example
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/cryptography-services.md
Encrypts data using AES with a session key and initialization vector (IV). This is commonly used for encrypting sensitive payloads like invoice data before transmission.
```java
// Generate AES-256 session key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey sessionKey = keyGen.generateKey();
// Generate random IV
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
// Prepare invoice data
byte[] invoiceXmlBytes = invoiceXml.getBytes(StandardCharsets.UTF_8);
// Encrypt
CryptographyService crypto = new DefaultCryptographyService();
byte[] encryptedInvoice = crypto.encryptAES(
sessionKey,
iv,
invoiceXmlBytes
);
// Convert to Base64 for API transmission
String encryptedInvoiceBase64 = Base64.getEncoder().encodeToString(
encryptedInvoice
);
String ivBase64 = Base64.getEncoder().encodeToString(iv);
```
--------------------------------
### Build KSeF Token Authentication Request (Java)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Constructs requests for authenticating with a previously generated KSeF token. Use this when you already have a valid KSeF token and need to authenticate a session.
```java
import pl.akmf.ksef.sdk.api.builders.auth.AuthKsefTokenRequestBuilder;
AuthKsefTokenRequest request = new AuthKsefTokenRequestBuilder()
.withToken("KSEF_TOKEN_VALUE_HERE")
.withContextIdentifier(contextId)
.build();
SignatureResponse response = client.authenticateByKSeFToken(request);
```
--------------------------------
### Handle Concurrent Modification (409)
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/errors.md
Catch KsefApiException with code 409 to manage concurrent modification errors, such as when a session state changes during an operation. This example retrieves the current session status for handling.
```java
try {
client.onlineSessionSendInvoice(refNumber, invoiceRequest, accessToken);
} catch (KsefApiException e) {
if (e.getCode() == 409) {
// Session closed or other concurrent modification
// Get current status
SessionStatusResponse status =
client.getSessionStatus(refNumber, accessToken);
System.err.println("Session status: " + status.getSessionStatus());
// Handle based on actual state
}
}
```
--------------------------------
### Set Custom Rate Limits
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/configuration.md
Configure custom request limits and window size for rate limiting. This is applicable only in test environments.
```java
import pl.akmf.ksef.sdk.client.model.limit.SetRateLimitsRequest;
SetRateLimitsRequest rateLimitRequest = new SetRateLimitsRequest();
rateLimitRequest.setRequestLimit(100); // Max requests per minute
rateLimitRequest.setWindowSizeSeconds(60);
client.setRateLimits(rateLimitRequest, accessToken);
```
--------------------------------
### Build Person Permission Grant Request
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/api-reference/builders.md
Use this builder to construct requests for granting permissions to individuals. It supports specifying person identifiers (PESEL), names, and individual or multiple permissions.
```java
import pl.akmf.ksef.sdk.api.builders.permission.person.GrantPersonPermissionsRequestBuilder;
GrantPersonPermissionsRequest request =
new GrantPersonPermissionsRequestBuilder()
.withPersonIdentifier("12345678901") // PESEL
.withPersonName("Jan Kowalski")
.withPermission("InvoiceRead")
.withPermission("InvoiceWrite")
.build();
OperationResponse response = client.grantsPermissionPerson(request, accessToken);
```
--------------------------------
### Implement Rate Limiting Retry Logic
Source: https://github.com/cirfmf/ksef-client-java/blob/main/_autodocs/errors.md
Handle TooManyRequestsApiException (429) by implementing a retry mechanism with backoff. This example extracts the 'Retry-After' header to determine the wait duration before retrying the operation, with a maximum retry count.
```java
private void retryWithBackoff(Supplier operation, int maxRetries) {
int retry = 0;
while (retry < maxRetries) {
try {
operation.get();
return;
} catch (TooManyRequestsApiException e) {
HttpHeaders headers = e.getResponseHeaders();
int delaySeconds = 5; // Default
if (headers != null && headers.containsKey("Retry-After")) {
delaySeconds = Integer.parseInt(
headers.get("Retry-After").get(0)
);
}
System.err.println("Rate limited, waiting " + delaySeconds + "s");
try {
Thread.sleep(delaySeconds * 1000L);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
retry++;
}
}
throw new RuntimeException("Max retries exceeded");
}
// Usage
retryWithBackoff(() -> {
client.queryInvoiceMetadata(0, 10, SortOrder.ASC, filters, accessToken);
return null;
}, 3);
```