Java SDK

The official `owlat-sdk` package provides a typed client for interacting with the Owlat API from any JVM application. Requires Java 11+.

The official owlat-sdk package provides a typed client for interacting with the Owlat API from any JVM application. Requires Java 11+.

Installation

<dependency>
    <groupId>com.owlat</groupId>
    <artifactId>owlat-sdk</artifactId>
    <version>0.1.0</version>
</dependency>
implementation 'com.owlat:owlat-sdk:0.1.0'

Quick start

import com.owlat.sdk.Owlat;
import com.owlat.sdk.model.contact.Contact;
import com.owlat.sdk.model.contact.CreateContactParams;

Owlat owlat = new Owlat("lm_live_...");

Contact contact = owlat.contacts().create(
    CreateContactParams.builder("mira@acme.io")
        .firstName("Mira")
        .lastName("Chen")
        .build()
);

You can also pass a full configuration object:

import com.owlat.sdk.OwlatConfig;
import java.time.Duration;

Owlat owlat = new Owlat(
    OwlatConfig.builder("lm_live_...")
        .baseUrl("https://your-deployment.convex.site")
        .timeout(Duration.ofSeconds(60))
        .build()
);

Resources

Contacts

Manage contacts in your audience.

// Create a contact
Contact contact = owlat.contacts().create(
    CreateContactParams.builder("mira@acme.io")
        .firstName("Mira")
        .lastName("Chen")
        .build()
);

// Get by ID or email
Contact found = owlat.contacts().get("mira@acme.io");

// Update a contact
Contact updated = owlat.contacts().update("mira@acme.io",
    UpdateContactParams.builder()
        .lastName("Chen-Lopez")
        .build()
);

// List with pagination
PaginatedResponse<Contact> page = owlat.contacts().list(
    PaginationParams.builder()
        .page(1)
        .limit(25)
        .sortBy("createdAt")
        .sortOrder("desc")
        .build()
);

// Delete a contact
DeleteContactResponse deleted = owlat.contacts().delete("mira@acme.io");

Transactional

Send transactional emails using pre-built templates.

import com.owlat.sdk.model.transactional.SendTransactionalParams;
import com.owlat.sdk.model.transactional.SendTransactionalResponse;

SendTransactionalResponse result = owlat.transactional().send(
    SendTransactionalParams.builder("buyer@example.com")
        .slug("order-confirmation")
        .dataVariables(Map.of(
            "orderId", "ORD-7291",
            "total", "$142.00"
        ))
        .language("en")
        .addToAudience(true)
        .build()
);

You can identify the template by slug or transactionalId. At least one must be provided.

Attachments

You can attach files using base64-encoded content or HTTPS URLs (max 10 files, 10 MB total):

import com.owlat.sdk.model.transactional.TransactionalAttachment;

SendTransactionalResponse result = owlat.transactional().send(
    SendTransactionalParams.builder("buyer@example.com")
        .slug("order-confirmation")
        .attachment(TransactionalAttachment.builder("invoice.pdf")
            .content(base64String)
            .contentType("application/pdf")
            .build())
        .attachment(TransactionalAttachment.builder("receipt.pdf")
            .url("https://your-api.com/receipts/ORD-7291.pdf")
            .build())
        .build()
);

Events

Send custom events to trigger automations and build segments.

import com.owlat.sdk.model.event.SendEventParams;
import com.owlat.sdk.model.event.SendEventResponse;

SendEventResponse result = owlat.events().send(
    SendEventParams.builder("mira@acme.io", "plan_upgraded")
        .eventProperties(Map.of(
            "plan", "pro",
            "mrr", 49
        ))
        .createContactIfNotExists(true)
        .build()
);

// result.getTriggeredAutomations() — list of automation IDs triggered

Lists

Manage mailing list memberships.

import com.owlat.sdk.model.list.*;

// Add a contact to a list
AddToListResponse added = owlat.lists().addContact(
    AddToListParams.builder("list_abc123")
        .email("mira@acme.io")
        .build()
);
// added.getDoiStatus() — NOT_REQUIRED, PENDING, or CONFIRMED

// Remove a contact from a list
RemoveFromListResponse removed = owlat.lists().removeContact(
    new RemoveFromListParams("list_abc123", "mira@acme.io")
);

Error handling

All exceptions extend OwlatException (unchecked) and include the HTTP status code plus rate limit info.

import com.owlat.sdk.exception.*;

try {
    owlat.contacts().get("nonexistent@example.com");
} catch (NotFoundException e) {
    System.err.println("Not found: " + e.getMessage());
} catch (AuthenticationException e) {
    System.err.println("Invalid API key");
} catch (RateLimitException e) {
    System.err.println("Rate limited. Retry after " + e.getRetryAfter() + "s");
} catch (ValidationException e) {
    System.err.println("Invalid request: " + e.getMessage());
} catch (ConflictException e) {
    System.err.println("Conflict: " + e.getMessage());
} catch (OwlatException e) {
    System.err.println("API error " + e.getStatusCode() + ": " + e.getMessage());
}
Exception classHTTP statusWhen
AuthenticationException401Invalid or missing API key
ValidationException400Request body fails validation
NotFoundException404Resource does not exist
ConflictException409Duplicate resource (e.g. existing email)
RateLimitException429Too many requests

Every exception exposes getRateLimit() which returns a RateLimitInfo with getLimit(), getRemaining(), and getReset().

Rate limit tracking

Rate limit headers are parsed automatically from every response. Access them through getRateLimit() on any exception, or inspect the response headers directly:

HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetSeconds until the window resets

Building from source

cd packages/sdk-java
mvn compile
mvn test

Using TypeScript?

See the TypeScript SDK reference for Node.js, Bun, and Deno integration.