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 class | HTTP status | When |
|---|---|---|
AuthenticationException | 401 | Invalid or missing API key |
ValidationException | 400 | Request body fails validation |
NotFoundException | 404 | Resource does not exist |
ConflictException | 409 | Duplicate resource (e.g. existing email) |
RateLimitException | 429 | Too 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:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Seconds until the window resets |
Building from source
cd packages/sdk-java
mvn compile
mvn test
See the TypeScript SDK reference for Node.js, Bun, and Deno integration.