diff --git a/CHANGELOG.md b/CHANGELOG.md
index f217169..4b7a135 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.1.0] - 2026-04-22
+
+### Added
+
+- `UpdateWebhookOptions.url()` — matches the renamed API field on `PUT /webhooks/{id}`
+
+### Changed
+
+- Webhook event types are now namespaced (e.g. `message.delivery`, `engagement.click`, `generation.generation_failure`). The server emits and accepts the namespaced form on both `POST` and `PUT`. Update any hard-coded event strings in `CreateWebhookOptions.events` / `UpdateWebhookOptions.events`.
+
+### Deprecated
+
+- `UpdateWebhookOptions.target()` / `getTarget()` — use `url()` / `getUrl()`. The builder still accepts `target` for source compatibility and serializes it as `url`, so existing callers keep working.
+
## [1.0.0] - 2026-04-21
### Added
@@ -57,6 +71,7 @@ Initial release.
- Bearer token auth, Gson-based JSON serialization
- Structured exceptions: `LettrException`, `LettrApiException`, `LettrValidationException`
+[1.1.0]: https://github.com/lettr/lettr-java/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/lettr/lettr-java/compare/v0.2.0...v1.0.0
[0.2.0]: https://github.com/lettr/lettr-java/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/lettr/lettr-java/releases/tag/v0.1.0
diff --git a/README.md b/README.md
index 81a60ea..7995286 100644
--- a/README.md
+++ b/README.md
@@ -297,7 +297,7 @@ Webhook webhook = lettr.webhooks().create(
.authUsername("user")
.authPassword("secret")
.eventsMode("selected")
- .events(List.of("delivery", "bounce"))
+ .events(List.of("message.delivery", "message.bounce"))
.build()
);
System.out.println("Webhook ID: " + webhook.getId());
@@ -315,7 +315,7 @@ Webhook webhook = lettr.webhooks().get("webhook-abc123");
Webhook updated = lettr.webhooks().update("webhook-abc123",
UpdateWebhookOptions.builder()
.name("Updated Webhook")
- .target("https://new.example.com/webhook")
+ .url("https://new.example.com/webhook")
.active(false)
.build()
);
diff --git a/gradle.properties b/gradle.properties
index 0827eec..186a9de 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.lettr
-VERSION=1.0.0
+VERSION=1.1.0
POM_ARTIFACT_ID=lettr-java
POM_NAME=Lettr Java SDK
POM_DESCRIPTION=Java SDK for the Lettr Email API
diff --git a/src/main/java/com/lettr/services/webhooks/model/UpdateWebhookOptions.java b/src/main/java/com/lettr/services/webhooks/model/UpdateWebhookOptions.java
index 88e1ac5..05eeb93 100644
--- a/src/main/java/com/lettr/services/webhooks/model/UpdateWebhookOptions.java
+++ b/src/main/java/com/lettr/services/webhooks/model/UpdateWebhookOptions.java
@@ -13,7 +13,7 @@
public class UpdateWebhookOptions {
private final String name;
- private final String target;
+ private final String url;
@SerializedName("auth_type") private final String authType;
@SerializedName("auth_username") private final String authUsername;
@@ -27,7 +27,7 @@ public class UpdateWebhookOptions {
private UpdateWebhookOptions(Builder builder) {
this.name = builder.name;
- this.target = builder.target;
+ this.url = builder.url;
this.authType = builder.authType;
this.authUsername = builder.authUsername;
this.authPassword = builder.authPassword;
@@ -44,7 +44,10 @@ public static Builder builder() {
}
@Nullable public String getName() { return name; }
- @Nullable public String getTarget() { return target; }
+ @Nullable public String getUrl() { return url; }
+ /** @deprecated use {@link #getUrl()} — the API field was renamed from {@code target} to {@code url}. */
+ @Deprecated
+ @Nullable public String getTarget() { return url; }
@Nullable public String getAuthType() { return authType; }
@Nullable public String getAuthUsername() { return authUsername; }
@Nullable public String getAuthPassword() { return authPassword; }
@@ -56,7 +59,7 @@ public static Builder builder() {
public static class Builder {
private String name;
- private String target;
+ private String url;
private String authType;
private String authUsername;
private String authPassword;
@@ -71,8 +74,14 @@ private Builder() {}
/** (optional) Sets the new webhook name. Max length: 255. */
@Nonnull public Builder name(@Nullable String name) { this.name = name; return this; }
- /** (optional) Sets the new webhook target URL. Max length: 2048. */
- @Nonnull public Builder target(@Nullable String target) { this.target = target; return this; }
+ /** (optional) Sets the new webhook URL. Max length: 2048. */
+ @Nonnull public Builder url(@Nullable String url) { this.url = url; return this; }
+
+ /**
+ * @deprecated use {@link #url(String)} — the API field was renamed from {@code target} to {@code url}.
+ */
+ @Deprecated
+ @Nonnull public Builder target(@Nullable String target) { this.url = target; return this; }
/** (optional) Sets the new authentication type. */
@Nonnull public Builder authType(@Nullable String authType) { this.authType = authType; return this; }
diff --git a/src/test/java/com/lettr/services/webhooks/WebhooksTest.java b/src/test/java/com/lettr/services/webhooks/WebhooksTest.java
index c3bf2e8..23961a6 100644
--- a/src/test/java/com/lettr/services/webhooks/WebhooksTest.java
+++ b/src/test/java/com/lettr/services/webhooks/WebhooksTest.java
@@ -66,7 +66,7 @@ void createWebhookOptionsBuildsWithAllFields() {
.authUsername("user")
.authPassword("pass")
.eventsMode("selected")
- .events(Arrays.asList("delivery", "bounce"))
+ .events(Arrays.asList("message.delivery", "message.bounce"))
.build();
assertEquals("Test Webhook", options.getName());
@@ -108,7 +108,7 @@ void updateWebhookOptionsBuildsWithNoFields() {
void updateWebhookOptionsBuildsWithAllFields() {
UpdateWebhookOptions options = UpdateWebhookOptions.builder()
.name("Updated")
- .target("https://new.example.com/webhook")
+ .url("https://new.example.com/webhook")
.authType("oauth2")
.oauthClientId("client-id")
.oauthClientSecret("secret")
@@ -118,11 +118,45 @@ void updateWebhookOptionsBuildsWithAllFields() {
.build();
assertEquals("Updated", options.getName());
- assertEquals("https://new.example.com/webhook", options.getTarget());
+ assertEquals("https://new.example.com/webhook", options.getUrl());
assertEquals("oauth2", options.getAuthType());
assertEquals(false, options.getActive());
}
+ @Test
+ @SuppressWarnings("deprecation")
+ void updateWebhookOptionsDeprecatedTargetStillWorks() {
+ UpdateWebhookOptions options = UpdateWebhookOptions.builder()
+ .target("https://legacy.example.com/webhook")
+ .build();
+
+ assertEquals("https://legacy.example.com/webhook", options.getUrl());
+ assertEquals("https://legacy.example.com/webhook", options.getTarget());
+ }
+
+ @Test
+ void updateWebhookOptionsSerializesUrlNotTarget() {
+ UpdateWebhookOptions options = UpdateWebhookOptions.builder()
+ .url("https://new.example.com/webhook")
+ .build();
+
+ String json = gson.toJson(options);
+ assertTrue(json.contains("\"url\""));
+ assertFalse(json.contains("\"target\""));
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ void updateWebhookOptionsDeprecatedTargetSerializesAsUrl() {
+ UpdateWebhookOptions options = UpdateWebhookOptions.builder()
+ .target("https://legacy.example.com/webhook")
+ .build();
+
+ String json = gson.toJson(options);
+ assertTrue(json.contains("\"url\""));
+ assertFalse(json.contains("\"target\""));
+ }
+
// --- Webhook deserialization ---
@Test