> ## Documentation Index
> Fetch the complete documentation index at: https://developers.uqpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Java SDK

> Install and configure the official UQPAY Java SDK to integrate payment, banking, and card issuance APIs.

The UQPAY Java SDK provides typed access to the UQPAY API, including automatic OAuth2 authentication, webhook verification, PGP-based authorization decision, and a sandbox simulator.

<Card title="GitHub" icon="java" href="https://github.com/uqpay/uqpay-sdk-java">
  com.uqpay.sdk:uqpay-sdk-java
</Card>

<Info>
  The SDK requires **Java 11** or higher, with **Maven 3.6+** or **Gradle 7+**.
</Info>

## Installation

<Tabs>
  <Tab title="Maven">
    ```xml theme={null}
    <dependency>
        <groupId>com.uqpay.sdk</groupId>
        <artifactId>uqpay-sdk-java</artifactId>
        <version>1.0.0</version>
    </dependency>
    ```
  </Tab>

  <Tab title="Gradle">
    ```groovy theme={null}
    implementation 'com.uqpay.sdk:uqpay-sdk-java:1.0.0'
    ```
  </Tab>
</Tabs>

## Quick start

```java theme={null}
import com.uqpay.sdk.v2.UqpayClient;

// Sandbox (for testing)
UqpayClient client = UqpayClient.sandbox("your-client-id", "your-api-key");

// Production
UqpayClient client = UqpayClient.production("your-client-id", "your-api-key");
```

## Authentication

The SDK handles OAuth2 authentication automatically. It fetches an access token using your `clientId` and `apiKey`, caches it, and refreshes it before expiry. You do not need to manage tokens manually.

## Configuration

### Custom HTTP client

```java theme={null}
import okhttp3.OkHttpClient;
import com.uqpay.sdk.v2.config.Configuration;
import com.uqpay.sdk.v2.config.Environment;

OkHttpClient httpClient = new OkHttpClient.Builder()
        .connectTimeout(Duration.ofSeconds(60))
        .readTimeout(Duration.ofSeconds(60))
        .build();

Configuration config = Configuration.builder()
        .clientId("your-client-id")
        .apiKey("your-api-key")
        .environment(Environment.PRODUCTION)
        .httpClient(httpClient)
        .build();

UqpayClient client = new UqpayClient(config);
```

### Environments

| Constant                 | Description                                     |
| ------------------------ | ----------------------------------------------- |
| `Environment.SANDBOX`    | Sandbox environment for testing and development |
| `Environment.PRODUCTION` | Production environment for live transactions    |

## Pagination

All list methods return a paginated response with `getData()`, `getTotalPages()`, and `getTotalItems()`:

```java theme={null}
ListCardsRequest req = new ListCardsRequest();
req.setPageNumber(1);
req.setPageSize(50);
ListCardsResponse page = client.issuing().getCards().list(req);

System.out.println(page.getData());       // List<Card>
System.out.println(page.getTotalPages()); // total number of pages
System.out.println(page.getTotalItems()); // total number of items
```

## Webhooks

Verify incoming webhook signatures from UQPAY:

```java theme={null}
import com.uqpay.sdk.v2.webhook.WebhookVerifier;
import com.uqpay.sdk.v2.webhook.Event;
import com.uqpay.sdk.v2.common.UqpayWebhookException;

WebhookVerifier verifier = new WebhookVerifier("your-webhook-secret");

try {
    Event event = verifier.verifyAndParse(
        requestBodyString,
        request.getHeader("x-signature"),
        request.getHeader("x-timestamp")
    );

    if (event.isCardTransactionEvent()) {
        // handle card transaction authorization, clearing, etc.
    } else if (Event.EVENT_NAME_CARDHOLDER_KYC.equals(event.getEventName())) {
        // handle KYC status update
    }
} catch (UqpayWebhookException e) {
    // signature invalid or timestamp expired
    response.setStatus(400);
}
```

The verifier checks the HMAC-SHA512 signature and rejects requests with a timestamp older than 300 seconds by default.

## Authorization decision (PGP)

Handle real-time card transaction authorization decisions. UQPAY sends PGP-encrypted transactions to your endpoint; the SDK decrypts them, calls your handler, and returns an encrypted response.

```java theme={null}
import com.uqpay.sdk.v2.issuing.AuthDecisionService;
import com.uqpay.sdk.v2.issuing.model.AuthDecisionConfig;
import com.uqpay.sdk.v2.issuing.model.AuthDecisionRequest;
import com.uqpay.sdk.v2.issuing.model.AuthDecisionResponse;

// Configure PGP keys (once at startup)
AuthDecisionConfig config = new AuthDecisionConfig(
    "./keys/my-private.asc",
    System.getenv("PGP_PASSPHRASE"),
    "./keys/uqpay-public.asc"
);

AuthDecisionService authDecision = client.issuing().getAuthDecision();
authDecision.configure(config);

// Handle a decision request
AuthDecisionHandler handler = (AuthDecisionRequest tx) -> {
    if (tx.getBillingAmount() > 10000) {
        return AuthDecisionResponse.decline(tx.getTransactionId(), "51");
    }
    return AuthDecisionResponse.approve(tx.getTransactionId());
};

// In your HTTP handler, pass the raw encrypted body string:
String encryptedResponse = authDecision.processRequest(requestBodyString, handler);
response.getWriter().write(encryptedResponse);
```

## Error handling

The SDK uses a hierarchy of exceptions:

| Exception               | Description                                                                |
| ----------------------- | -------------------------------------------------------------------------- |
| `UqpayException`        | Base exception for all SDK errors                                          |
| `UqpayApiException`     | API returned an error response (includes HTTP status, error code, message) |
| `UqpayAuthException`    | Authentication failed (invalid credentials, token refresh failure)         |
| `UqpayNetworkException` | Network-level failure (timeout, connection refused)                        |
| `UqpayWebhookException` | Webhook signature verification failed                                      |

```java theme={null}
try {
    Balance balance = client.banking().getBalances().get("SGD");
} catch (UqpayApiException e) {
    System.err.printf("API error: status=%d, code=%s, message=%s%n",
            e.getStatusCode(), e.getCode(), e.getMessage());
} catch (UqpayAuthException e) {
    System.err.println("Authentication failed: " + e.getMessage());
} catch (UqpayNetworkException e) {
    System.err.println("Network error: " + e.getMessage());
} catch (UqpayException e) {
    System.err.println("SDK error: " + e.getMessage());
}
```
