> ## Documentation Index
> Fetch the complete documentation index at: https://torpedo.co.mz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Java SDK

> Send email and SMS from Java 17 with the official Torpedo SDK

The Java SDK provides blocking and `CompletableFuture` clients for Torpedo's email and SMS API.

## Install

<CodeGroup>
  ```xml Maven theme={null}
  <dependency>
    <groupId>mz.co.torpedo</groupId>
    <artifactId>torpedo-java</artifactId>
    <version>0.1.0</version>
  </dependency>
  ```

  ```kotlin Gradle theme={null}
  implementation("mz.co.torpedo:torpedo-java:0.1.0")
  ```
</CodeGroup>

Java 17 or newer is required.

## Create a client

```java theme={null}
import mz.co.torpedo.TorpedoClient;

var torpedo = TorpedoClient.builder()
    .apiKey(System.getenv("TORPEDO_API_KEY"))
    .build();
```

Create one client and reuse it. Clients and resource objects are thread-safe.

## Send email

```java theme={null}
import mz.co.torpedo.models.SendEmailRequest;

var email = torpedo.emails().send(
    SendEmailRequest.builder()
        .from("Acme <hello@myapp.com>")
        .to("user@example.com")
        .subject("Welcome")
        .html("<h1>Welcome!</h1>")
        .text("Welcome!")
        .build()
);

System.out.println(email.id());
```

## Send a batch

```java theme={null}
import mz.co.torpedo.models.SendEmailBatchRequest;

var queued = torpedo.emails().sendBatch(
    SendEmailBatchRequest.builder()
        .addEmail(firstEmail)
        .addEmail(secondEmail)
        .idempotencyKey("customer-import-2026-07-31")
        .build()
);
```

## Send SMS

```java theme={null}
import mz.co.torpedo.models.SendSmsRequest;

var sms = torpedo.sms().send(
    SendSmsRequest.builder()
        .to("+258841234567")
        .body("Your code is 482910.")
        .build()
);
```

## Async calls

```java theme={null}
import mz.co.torpedo.TorpedoAsyncClient;

var asyncTorpedo = TorpedoAsyncClient.builder()
    .apiKey(System.getenv("TORPEDO_API_KEY"))
    .build();

asyncTorpedo.emails().send(request)
    .thenAccept(message -> System.out.println(message.id()));
```

Cancelling the returned future cancels the active HTTP request and prevents later retries.

## Pagination

```java theme={null}
var page = torpedo.emails().list(
    ListOptions.builder().limit(25).build()
);

if (page.meta().hasMore()) {
  var next = torpedo.emails().list(
      ListOptions.builder()
          .cursor(page.meta().nextCursor().orElseThrow())
          .limit(25)
          .build()
  );
}
```

## Errors and retries

```java theme={null}
try {
  torpedo.emails().send(request);
} catch (TorpedoApiException error) {
  System.err.println(error.statusCode());
  error.errors().forEach(item ->
      System.err.println(item.code() + ": " + item.message()));
}
```

The SDK retries network errors, `429`, and `5xx` responses three times by default. Every send has one idempotency key that is reused across retry attempts. Configure `.timeout(Duration)` and `.maxRetries(int)` on the client builder.

## Verify webhooks

```java theme={null}
boolean valid = WebhookVerifier.verify(rawRequestBody, signingSecret, signatureHeader);
```

Always pass the raw request bytes before JSON parsing.
