diff --git a/src/main/java/com/resend/services/contacts/ContactSegments.java b/src/main/java/com/resend/services/contacts/ContactSegments.java
new file mode 100644
index 0000000..ff73d9c
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/ContactSegments.java
@@ -0,0 +1,137 @@
+package com.resend.services.contacts;
+
+import com.resend.core.exception.ResendException;
+import com.resend.core.helper.URLHelper;
+import com.resend.core.net.AbstractHttpResponse;
+import com.resend.core.net.HttpMethod;
+import com.resend.core.net.ListParams;
+import com.resend.core.service.BaseService;
+import com.resend.services.contacts.model.*;
+import okhttp3.MediaType;
+
+/**
+ * Represents the Contact Segments sub-service.
+ * Handles operations for managing contact membership in segments.
+ */
+public class ContactSegments extends BaseService {
+
+ /**
+ * Constructs an instance of the {@code ContactSegments} class.
+ *
+ * @param apiKey The apiKey used for authentication.
+ */
+ public ContactSegments(final String apiKey) {
+ super(apiKey);
+ }
+
+ /**
+ * Adds an existing contact to a segment.
+ *
+ * @param options The options containing the contact identifier (id or email) and segment ID.
+ * @return The AddContactToSegmentResponseSuccess with the segment ID.
+ * @throws ResendException If an error occurs during the segment addition process.
+ */
+ public AddContactToSegmentResponseSuccess add(AddContactToSegmentOptions options) throws ResendException {
+ if ((options.getId() == null && options.getEmail() == null) ||
+ (options.getId() != null && options.getEmail() != null)) {
+ throw new IllegalArgumentException("Either 'id' or 'email' must be provided, but not both.");
+ }
+
+ if (options.getSegmentId() == null || options.getSegmentId().isEmpty()) {
+ throw new IllegalArgumentException("Segment ID must be provided");
+ }
+
+ String contactIdOrEmail = options.getId() != null ? options.getId() : options.getEmail();
+ String endpoint = "/contacts/" + contactIdOrEmail + "/segments/" + options.getSegmentId();
+
+ AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.POST, "", MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, AddContactToSegmentResponseSuccess.class);
+ }
+
+ /**
+ * Removes an existing contact from a segment.
+ *
+ * @param options The options containing the contact identifier (id or email) and segment ID.
+ * @return The RemoveContactFromSegmentResponseSuccess with the segment ID and deletion status.
+ * @throws ResendException If an error occurs during the segment removal process.
+ */
+ public RemoveContactFromSegmentResponseSuccess remove(RemoveContactFromSegmentOptions options) throws ResendException {
+ if ((options.getId() == null && options.getEmail() == null) ||
+ (options.getId() != null && options.getEmail() != null)) {
+ throw new IllegalArgumentException("Either 'id' or 'email' must be provided, but not both.");
+ }
+
+ if (options.getSegmentId() == null || options.getSegmentId().isEmpty()) {
+ throw new IllegalArgumentException("Segment ID must be provided");
+ }
+
+ String contactIdOrEmail = options.getId() != null ? options.getId() : options.getEmail();
+ String endpoint = "/contacts/" + contactIdOrEmail + "/segments/" + options.getSegmentId();
+
+ AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.DELETE, "", null);
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, RemoveContactFromSegmentResponseSuccess.class);
+ }
+
+ /**
+ * Retrieves a list of segments that a contact belongs to.
+ *
+ * @param contactIdOrEmail The contact ID or email address.
+ * @return The ListContactSegmentsResponseSuccess with the list of segments.
+ * @throws ResendException If an error occurs during the segment list retrieval process.
+ */
+ public ListContactSegmentsResponseSuccess list(String contactIdOrEmail) throws ResendException {
+ if (contactIdOrEmail == null || contactIdOrEmail.isEmpty()) {
+ throw new IllegalArgumentException("Contact ID or email must be provided");
+ }
+
+ String endpoint = "/contacts/" + contactIdOrEmail + "/segments";
+ AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, ListContactSegmentsResponseSuccess.class);
+ }
+
+ /**
+ * Retrieves a paginated list of segments that a contact belongs to.
+ *
+ * @param contactId The contact ID.
+ * @param params The params used to customize the list.
+ * @return The ListContactSegmentsResponseSuccess with the paginated list of segments.
+ * @throws ResendException If an error occurs during the segment list retrieval process.
+ */
+ public ListContactSegmentsResponseSuccess list(String contactId, ListParams params) throws ResendException {
+ if (contactId == null || contactId.isEmpty()) {
+ throw new IllegalArgumentException("Contact ID must be provided");
+ }
+
+ String pathWithQuery = "/contacts/" + contactId + "/segments" + URLHelper.parse(params);
+ AbstractHttpResponse response = httpClient.perform(pathWithQuery, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, ListContactSegmentsResponseSuccess.class);
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/ContactTopics.java b/src/main/java/com/resend/services/contacts/ContactTopics.java
new file mode 100644
index 0000000..6e54c19
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/ContactTopics.java
@@ -0,0 +1,108 @@
+package com.resend.services.contacts;
+
+import com.resend.core.exception.ResendException;
+import com.resend.core.helper.URLHelper;
+import com.resend.core.net.AbstractHttpResponse;
+import com.resend.core.net.HttpMethod;
+import com.resend.core.net.ListParams;
+import com.resend.core.service.BaseService;
+import com.resend.services.contacts.model.ListContactTopicsResponse;
+import com.resend.services.contacts.model.UpdateContactTopicsOptions;
+import com.resend.services.contacts.model.UpdateContactTopicsResponse;
+import okhttp3.MediaType;
+
+/**
+ * Represents the Contact Topics sub-service.
+ * Handles operations for managing contact topic subscriptions.
+ */
+public class ContactTopics extends BaseService {
+
+ /**
+ * Constructs an instance of the {@code ContactTopics} class.
+ *
+ * @param apiKey The apiKey used for authentication.
+ */
+ public ContactTopics(final String apiKey) {
+ super(apiKey);
+ }
+
+ /**
+ * Retrieves a list of topic subscriptions for a contact.
+ *
+ * @param contactIdOrEmail The contact ID or email address.
+ * @return A ListContactTopicsResponse containing the list of topic subscriptions.
+ * @throws ResendException If an error occurs during the topic list retrieval process.
+ */
+ public ListContactTopicsResponse list(String contactIdOrEmail) throws ResendException {
+ if (contactIdOrEmail == null || contactIdOrEmail.isEmpty()) {
+ throw new IllegalArgumentException("Contact ID or email must be provided");
+ }
+
+ AbstractHttpResponse response = this.httpClient.perform("/contacts/" + contactIdOrEmail + "/topics", super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, ListContactTopicsResponse.class);
+ }
+
+ /**
+ * Retrieves a paginated list of topic subscriptions for a contact.
+ *
+ * @param contactIdOrEmail The contact ID or email address.
+ * @param params The params used to customize the list.
+ * @return A ListContactTopicsResponse containing the paginated list of topic subscriptions.
+ * @throws ResendException If an error occurs during the topic list retrieval process.
+ */
+ public ListContactTopicsResponse list(String contactIdOrEmail, ListParams params) throws ResendException {
+ if (contactIdOrEmail == null || contactIdOrEmail.isEmpty()) {
+ throw new IllegalArgumentException("Contact ID or email must be provided");
+ }
+
+ String pathWithQuery = "/contacts/" + contactIdOrEmail + "/topics" + URLHelper.parse(params);
+ AbstractHttpResponse response = this.httpClient.perform(pathWithQuery, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, ListContactTopicsResponse.class);
+ }
+
+ /**
+ * Updates topic subscriptions for a contact.
+ *
+ * @param options The options containing the contact identifier and topic updates.
+ * @return The UpdateContactTopicsResponse with the contact ID.
+ * @throws ResendException If an error occurs during the topic update process.
+ */
+ public UpdateContactTopicsResponse update(UpdateContactTopicsOptions options) throws ResendException {
+ if ((options.getId() == null && options.getEmail() == null) ||
+ (options.getId() != null && options.getEmail() != null)) {
+ throw new IllegalArgumentException("Either 'id' or 'email' must be provided, but not both.");
+ }
+
+ if (options.getTopics() == null || options.getTopics().isEmpty()) {
+ throw new IllegalArgumentException("Topics list must not be empty");
+ }
+
+ String contactIdOrEmail = options.getId() != null ? options.getId() : options.getEmail();
+
+ // Serialize just the topics array (not the whole options object)
+ String payload = super.resendMapper.writeValue(options.getTopics());
+ AbstractHttpResponse response = httpClient.perform("/contacts/" + contactIdOrEmail + "/topics", super.apiKey, HttpMethod.PATCH, payload, MediaType.get("application/json"));
+
+ if (!response.isSuccessful()) {
+ throw new ResendException(response.getCode(), response.getBody());
+ }
+
+ String responseBody = response.getBody();
+
+ return resendMapper.readValue(responseBody, UpdateContactTopicsResponse.class);
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/Contacts.java b/src/main/java/com/resend/services/contacts/Contacts.java
index 22f6071..a67a068 100644
--- a/src/main/java/com/resend/services/contacts/Contacts.java
+++ b/src/main/java/com/resend/services/contacts/Contacts.java
@@ -10,10 +10,34 @@
import okhttp3.MediaType;
/**
- * Represents the Resend Contacts module.
+ * Represents the Resend Contacts module.
+ *
+ * This service handles global contact operations (CRUD for contacts not associated with specific segments).
+ * For specialized operations, use the following sub-services:
+ *
+ *
+ * - {@link #segments()} - Manage contact membership in segments (add/remove contacts from segments)
+ * - {@link #topics()} - Manage contact topic subscriptions (list and update topic preferences)
+ *
+ *
+ * Global Contact Operations:
+ *
+ * - {@link #create(CreateContactOptions)} - Create a global contact
+ * - {@link #list()} - List all global contacts
+ * - {@link #list(ListParams)} - List global contacts with pagination
+ * - {@link #get(String)} - Get a global contact by ID or email
+ * - {@link #update(UpdateContactOptions)} - Update a global contact
+ * - {@link #remove(String)} - Remove a global contact
+ *
+ *
+ * Migration Note: Methods that accept {@code segmentId} or {@code audienceId} parameters
+ * are deprecated. Use the Segments service for segment-specific operations instead.
*/
public class Contacts extends BaseService {
+ private ContactSegments contactSegments;
+ private ContactTopics contactTopics;
+
/**
* Constructs an instance of the {@code Contacts} class.
*
@@ -24,22 +48,46 @@ public Contacts(final String apiKey) {
}
/**
- * Creates a Contact.
+ * Returns the ContactSegments sub-service for managing contact segment memberships.
+ *
+ * @return The ContactSegments service instance.
+ */
+ public ContactSegments segments() {
+ if (this.contactSegments == null) {
+ this.contactSegments = new ContactSegments(this.apiKey);
+ }
+ return this.contactSegments;
+ }
+
+ /**
+ * Returns the ContactTopics sub-service for managing contact topic subscriptions.
+ *
+ * @return The ContactTopics service instance.
+ */
+ public ContactTopics topics() {
+ if (this.contactTopics == null) {
+ this.contactTopics = new ContactTopics(this.apiKey);
+ }
+ return this.contactTopics;
+ }
+
+ /**
+ * Creates a global contact (not associated with any segment).
+ *
+ * To add a contact to a segment, first create the global contact using this method,
+ * then use {@code contacts().segments().add(options)} to add it to specific segments.
+ *
+ * Note: The {@code segmentId} and {@code audienceId} fields in {@code CreateContactOptions}
+ * are ignored. Use the workflow above for segment membership.
*
* @param createContactOptions The Contact details.
* @return The details of the created contact.
* @throws ResendException If an error occurs during the Contact creation process.
*/
public CreateContactResponseSuccess create(CreateContactOptions createContactOptions) throws ResendException {
- String segmentId = createContactOptions.getSegmentId() != null ? createContactOptions.getSegmentId() : createContactOptions.getAudienceId();
String payload = super.resendMapper.writeValue(createContactOptions);
- // Use /contacts for global contacts (when no segment ID is provided)
- String endpoint = (segmentId == null || segmentId.isEmpty())
- ? "/contacts"
- : "/segments/" + segmentId + "/contacts";
-
- AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.POST, payload, MediaType.get("application/json"));
+ AbstractHttpResponse response = httpClient.perform("/contacts", super.apiKey, HttpMethod.POST, payload, MediaType.get("application/json"));
if (!response.isSuccessful()) {
throw new ResendException(response.getCode(), response.getBody());
@@ -50,12 +98,18 @@ public CreateContactResponseSuccess create(CreateContactOptions createContactOpt
}
/**
- * Retrieves a list of contacts and returns a ListContactsResponseSuccess.
+ * Retrieves a list of contacts in a segment.
+ *
+ * @deprecated This method is deprecated. Segment-related operations have been moved to dedicated services.
+ * For segment-specific contact operations, use the Segments service instead:
+ * {@code resend.segments().get(segmentId)} or contact operations through the Segments API.
+ * This method will be removed in a future version.
*
* @param segmentId The id of the segment (formerly known as audienceId).
* @return A ListContactsResponseSuccess containing the list of contacts.
* @throws ResendException If an error occurs during the contacts list retrieval process.
*/
+ @Deprecated
public ListContactsResponseSuccess list(String segmentId) throws ResendException {
AbstractHttpResponse response = this.httpClient.perform("/segments/" + segmentId + "/contacts" , super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
@@ -69,13 +123,19 @@ public ListContactsResponseSuccess list(String segmentId) throws ResendException
}
/**
- * Retrieves a paginated list of contacts and returns a ListContactsResponseSuccess.
+ * Retrieves a paginated list of contacts in a segment.
+ *
+ * @deprecated This method is deprecated. Segment-related operations have been moved to dedicated services.
+ * For segment-specific contact operations, use the Segments service instead:
+ * {@code resend.segments().get(segmentId)} or contact operations through the Segments API.
+ * This method will be removed in a future version.
*
* @param segmentId The id of the segment (formerly known as audienceId).
* @param params The params used to customize the list.
* @return A ListContactsResponseSuccess containing the paginated list of contacts.
* @throws ResendException If an error occurs during the contacts list retrieval process.
*/
+ @Deprecated
public ListContactsResponseSuccess list(String segmentId, ListParams params) throws ResendException {
String pathWithQuery = "/segments/" + segmentId + "/contacts" + URLHelper.parse(params);
AbstractHttpResponse response = this.httpClient.perform(pathWithQuery, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
@@ -128,15 +188,18 @@ public ListContactsResponseSuccess list(ListParams params) throws ResendExceptio
}
/**
- * Retrieves a contact by its unique identifier.
+ * Retrieves a global contact by its unique identifier.
+ *
+ * Note: The {@code segmentId} and {@code audienceId} fields in {@code GetContactOptions}
+ * are ignored. This method only retrieves global contacts. Use {@link #get(String)} for a simpler API.
*
- * @param params The object containing:
- * – {@code audienceId}: the audience to which the contact belongs
- * – Either {@code id}: the contact's id
- * or {@code email}: the contact's email address
+ * @deprecated Use {@link #get(String)} instead for global contacts.
+ *
+ * @param params The object containing either {@code id} or {@code email} of the contact.
* @return The retrieved contact details.
* @throws ResendException If an error occurs while retrieving the contact.
*/
+ @Deprecated
public GetContactResponseSuccess get(GetContactOptions params) throws ResendException {
String id = params.getId();
String email = params.getEmail();
@@ -146,14 +209,8 @@ public GetContactResponseSuccess get(GetContactOptions params) throws ResendExce
}
String contactIdentifier = (id != null && !id.isEmpty()) ? id : email;
- String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId();
-
- // Use /contacts for global contacts (when no segment ID is provided)
- String endpoint = (segmentId == null || segmentId.isEmpty())
- ? "/contacts/" + contactIdentifier
- : "/segments/" + segmentId + "/contacts/" + contactIdentifier;
- AbstractHttpResponse response = this.httpClient.perform(endpoint, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
+ AbstractHttpResponse response = this.httpClient.perform("/contacts/" + contactIdentifier, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json"));
if (!response.isSuccessful()) {
throw new ResendException(response.getCode(), response.getBody());
@@ -188,12 +245,18 @@ public GetContactResponseSuccess get(String contactIdOrEmail) throws ResendExcep
}
/**
- * Deletes a contact based on the provided contact ID or email.
+ * Deletes a global contact based on the provided contact ID or email.
+ *
+ * Note: The {@code segmentId} and {@code audienceId} fields in {@code RemoveContactOptions}
+ * are ignored. This method only removes global contacts. Use {@link #remove(String)} for a simpler API.
+ *
+ * @deprecated Use {@link #remove(String)} instead for global contacts.
*
* @param params The object with identifier of the contact to delete.
* @return The RemoveContactsResponseSuccess with the details of the removed contact.
* @throws ResendException If an error occurs during the contact deletion process.
*/
+ @Deprecated
public RemoveContactResponseSuccess remove(RemoveContactOptions params) throws ResendException {
if ((params.getId() == null && params.getEmail() == null) ||
(params.getId() != null && params.getEmail() != null)) {
@@ -201,14 +264,8 @@ public RemoveContactResponseSuccess remove(RemoveContactOptions params) throws R
}
String pathParameter = params.getId() != null ? params.getId() : params.getEmail();
- String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId();
-
- // Use /contacts for global contacts (when no segment ID is provided)
- String endpoint = (segmentId == null || segmentId.isEmpty())
- ? "/contacts/" + pathParameter
- : "/segments/" + segmentId + "/contacts/" + pathParameter;
- AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.DELETE, "", null);
+ AbstractHttpResponse response = httpClient.perform("/contacts/" + pathParameter, super.apiKey, HttpMethod.DELETE, "", null);
if (!response.isSuccessful()) {
throw new ResendException(response.getCode(), response.getBody());
@@ -244,7 +301,10 @@ public RemoveContactResponseSuccess remove(String contactId) throws ResendExcept
}
/**
- * Updates a contact based on the provided contact ID or email.
+ * Updates a global contact based on the provided contact ID or email.
+ *
+ * Note: The {@code segmentId} and {@code audienceId} fields in {@code UpdateContactOptions}
+ * are ignored. This method only updates global contacts.
*
* @param params The object with identifier of the contact to patch.
* @return The UpdateContactResponseSuccess with the details of the patched contact.
@@ -257,15 +317,9 @@ public UpdateContactResponseSuccess update(UpdateContactOptions params) throws R
}
String pathParameter = params.getId() != null ? params.getId() : params.getEmail();
- String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId();
-
- // Use /contacts for global contacts (when no segment ID is provided)
- String endpoint = (segmentId == null || segmentId.isEmpty())
- ? "/contacts/" + pathParameter
- : "/segments/" + segmentId + "/contacts/" + pathParameter;
String payload = super.resendMapper.writeValue(params);
- AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.PATCH, payload, MediaType.get("application/json"));
+ AbstractHttpResponse response = httpClient.perform("/contacts/" + pathParameter, super.apiKey, HttpMethod.PATCH, payload, MediaType.get("application/json"));
if (!response.isSuccessful()) {
throw new ResendException(response.getCode(), response.getBody());
@@ -279,6 +333,11 @@ public UpdateContactResponseSuccess update(UpdateContactOptions params) throws R
/**
* Retrieves a list of topic subscriptions for a contact.
*
+ * @deprecated This method is deprecated. Topics related operations have been moved to dedicated services.
+ * For contact-topics operations, use the Contacts service instead:
+ * {@code resend.contacts().topics.list(contactIdOrEmail)}.
+ * This method will be removed in a future version.
+ *
* @param contactIdOrEmail The contact ID or email address.
* @return A ListContactTopicsResponse containing the list of topic subscriptions.
* @throws ResendException If an error occurs during the topic list retrieval process.
@@ -302,6 +361,11 @@ public ListContactTopicsResponse getTopics(String contactIdOrEmail) throws Resen
/**
* Retrieves a paginated list of topic subscriptions for a contact.
*
+ * @deprecated This method is deprecated. Topics related operations have been moved to dedicated services.
+ * For contact-topics operations, use the Contacts service instead:
+ * {@code resend.contacts().topics.list(contactIdOrEmail, params)}.
+ * This method will be removed in a future version.
+ *
* @param contactIdOrEmail The contact ID or email address.
* @param params The params used to customize the list.
* @return A ListContactTopicsResponse containing the paginated list of topic subscriptions.
@@ -327,6 +391,11 @@ public ListContactTopicsResponse getTopics(String contactIdOrEmail, ListParams p
/**
* Updates topic subscriptions for a contact.
*
+ * @deprecated This method is deprecated. Topics related operations have been moved to dedicated services.
+ * For contact-topics operations, use the Contacts service instead:
+ * {@code resend.contacts().topics.list(options)}.
+ * This method will be removed in a future version.
+ *
* @param options The options containing the contact identifier and topic updates.
* @return The UpdateContactTopicsResponse with the contact ID.
* @throws ResendException If an error occurs during the topic update process.
diff --git a/src/main/java/com/resend/services/contacts/model/AddContactToSegmentOptions.java b/src/main/java/com/resend/services/contacts/model/AddContactToSegmentOptions.java
new file mode 100644
index 0000000..c999186
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/AddContactToSegmentOptions.java
@@ -0,0 +1,125 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Represents the options for adding a contact to a segment.
+ */
+public class AddContactToSegmentOptions {
+
+ /**
+ * The contact ID (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String id;
+
+ /**
+ * The contact email address (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String email;
+
+ /**
+ * The segment ID to add the contact to (required).
+ */
+ @JsonIgnore
+ private String segmentId;
+
+ /**
+ * Constructs a new AddContactToSegmentOptions using the builder.
+ *
+ * @param builder The builder to construct from.
+ */
+ private AddContactToSegmentOptions(Builder builder) {
+ this.id = builder.id;
+ this.email = builder.email;
+ this.segmentId = builder.segmentId;
+ }
+
+ /**
+ * Gets the contact ID.
+ *
+ * @return The contact ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the contact email.
+ *
+ * @return The contact email.
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Gets the segment ID.
+ *
+ * @return The segment ID.
+ */
+ public String getSegmentId() {
+ return segmentId;
+ }
+
+ /**
+ * Creates a new Builder for constructing AddContactToSegmentOptions.
+ *
+ * @return A new Builder instance.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder class for constructing AddContactToSegmentOptions instances.
+ */
+ public static class Builder {
+ private String id;
+ private String email;
+ private String segmentId;
+
+ /**
+ * Sets the contact ID.
+ *
+ * @param id The contact ID.
+ * @return This builder instance.
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Sets the contact email.
+ *
+ * @param email The contact email.
+ * @return This builder instance.
+ */
+ public Builder email(String email) {
+ this.email = email;
+ return this;
+ }
+
+ /**
+ * Sets the segment ID.
+ *
+ * @param segmentId The segment ID.
+ * @return This builder instance.
+ */
+ public Builder segmentId(String segmentId) {
+ this.segmentId = segmentId;
+ return this;
+ }
+
+ /**
+ * Builds the AddContactToSegmentOptions instance.
+ *
+ * @return A new AddContactToSegmentOptions instance.
+ */
+ public AddContactToSegmentOptions build() {
+ return new AddContactToSegmentOptions(this);
+ }
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/AddContactToSegmentResponseSuccess.java b/src/main/java/com/resend/services/contacts/model/AddContactToSegmentResponseSuccess.java
new file mode 100644
index 0000000..b3e7b1f
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/AddContactToSegmentResponseSuccess.java
@@ -0,0 +1,33 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents the successful response from adding a contact to a segment.
+ */
+public class AddContactToSegmentResponseSuccess {
+
+ /**
+ * The segment ID.
+ */
+ @JsonProperty("id")
+ private String id;
+
+ /**
+ * Gets the segment ID.
+ *
+ * @return The segment ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the segment ID.
+ *
+ * @param id The segment ID.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/ContactOptions.java b/src/main/java/com/resend/services/contacts/model/ContactOptions.java
index f60744d..ec88e5b 100644
--- a/src/main/java/com/resend/services/contacts/model/ContactOptions.java
+++ b/src/main/java/com/resend/services/contacts/model/ContactOptions.java
@@ -1,10 +1,15 @@
package com.resend.services.contacts.model;
+import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Common superclass for contact options.
+ *
+ * Note: These option classes are for global contact operations only.
+ * Segment-related fields are ignored.
*/
+@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class ContactOptions {
/**
@@ -15,7 +20,7 @@ public abstract class ContactOptions {
/**
* The audience_id of the contact options
- * @deprecated Use {@link #segmentId} instead.
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
@Deprecated
@JsonProperty("audience_id")
@@ -23,7 +28,9 @@ public abstract class ContactOptions {
/**
* The segment_id of the contact options
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
+ @Deprecated
@JsonProperty("segment_id")
protected final String segmentId;
@@ -58,7 +65,7 @@ public String getId() {
* Get the audienceId of the ContactOptions.
*
* @return The audienceId of the ContactOptions.
- * @deprecated Use {@link #getSegmentId()} instead.
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
@Deprecated
public String getAudienceId() {
@@ -69,7 +76,9 @@ public String getAudienceId() {
* Get the segmentId of the ContactOptions.
*
* @return The segmentId of the ContactOptions.
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
+ @Deprecated
public String getSegmentId() {
return segmentId;
}
@@ -125,7 +134,7 @@ public B id(String id) {
*
* @param audienceId The audienceId of the ContactOptions.
* @return The builder instance.
- * @deprecated Use {@link #segmentId(String)} instead.
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
@Deprecated
public B audienceId(String audienceId) {
@@ -138,7 +147,9 @@ public B audienceId(String audienceId) {
*
* @param segmentId The segmentId of the ContactOptions.
* @return The builder instance.
+ * @deprecated This field is ignored. Use ContactSegments service for segment operations.
*/
+ @Deprecated
public B segmentId(String segmentId) {
this.segmentId = segmentId;
return self();
diff --git a/src/main/java/com/resend/services/contacts/model/ContactSegment.java b/src/main/java/com/resend/services/contacts/model/ContactSegment.java
new file mode 100644
index 0000000..d47fea6
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/ContactSegment.java
@@ -0,0 +1,100 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents a segment that a contact belongs to.
+ */
+public class ContactSegment {
+
+ /**
+ * The segment ID.
+ */
+ @JsonProperty("id")
+ private String id;
+
+ /**
+ * The segment name.
+ */
+ @JsonProperty("name")
+ private String name;
+
+ /**
+ * The segment creation timestamp.
+ */
+ @JsonProperty("created_at")
+ private String createdAt;
+
+ /**
+ * Default constructor.
+ */
+ public ContactSegment() {
+ }
+
+ /**
+ * Constructor with all fields.
+ *
+ * @param id The segment ID.
+ * @param name The segment name.
+ * @param createdAt The segment creation timestamp.
+ */
+ public ContactSegment(String id, String name, String createdAt) {
+ this.id = id;
+ this.name = name;
+ this.createdAt = createdAt;
+ }
+
+ /**
+ * Gets the segment ID.
+ *
+ * @return The segment ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the segment ID.
+ *
+ * @param id The segment ID.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the segment name.
+ *
+ * @return The segment name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the segment name.
+ *
+ * @param name The segment name.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the segment creation timestamp.
+ *
+ * @return The segment creation timestamp.
+ */
+ public String getCreatedAt() {
+ return createdAt;
+ }
+
+ /**
+ * Sets the segment creation timestamp.
+ *
+ * @param createdAt The segment creation timestamp.
+ */
+ public void setCreatedAt(String createdAt) {
+ this.createdAt = createdAt;
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/CreateContactOptions.java b/src/main/java/com/resend/services/contacts/model/CreateContactOptions.java
index 88e5022..5be69bf 100644
--- a/src/main/java/com/resend/services/contacts/model/CreateContactOptions.java
+++ b/src/main/java/com/resend/services/contacts/model/CreateContactOptions.java
@@ -1,10 +1,20 @@
package com.resend.services.contacts.model;
+import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
- * Represents a request to create a contact.
+ * Represents a request to create a global contact.
+ *
+ * Note: This class is for creating global contacts only.
+ * To add a contact to a segment, use the workflow:
+ *
+ * - Create global contact: {@code resend.contacts().create(options)}
+ * - Add to segment: {@code resend.contacts().segments().add(options)}
+ *
+ *
*/
+@JsonInclude(JsonInclude.Include.NON_NULL)
public class CreateContactOptions {
@JsonProperty("audience_id")
@@ -12,6 +22,7 @@ public class CreateContactOptions {
private final String audienceId;
@JsonProperty("segment_id")
+ @Deprecated
private final String segmentId;
@JsonProperty("email")
@@ -55,7 +66,10 @@ public String getAudienceId() {
* Get the segment ID of the contact.
*
* @return The segment ID of the contact.
+ * @deprecated This field is ignored when creating global contacts.
+ * Use {@code resend.contacts().segments().add(options)} to add contacts to segments.
*/
+ @Deprecated
public String getSegmentId() {
return segmentId;
}
@@ -134,7 +148,10 @@ public Builder audienceId(String audienceId) {
*
* @param segmentId The segment ID of the contact.
* @return The builder instance.
+ * @deprecated This field is ignored when creating global contacts.
+ * Use {@code resend.contacts().segments().add(options)} to add contacts to segments.
*/
+ @Deprecated
public Builder segmentId(String segmentId) {
this.segmentId = segmentId;
return this;
diff --git a/src/main/java/com/resend/services/contacts/model/ListContactSegmentsOptions.java b/src/main/java/com/resend/services/contacts/model/ListContactSegmentsOptions.java
new file mode 100644
index 0000000..d0acc2a
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/ListContactSegmentsOptions.java
@@ -0,0 +1,97 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Represents the options for listing segments a contact belongs to.
+ */
+public class ListContactSegmentsOptions {
+
+ /**
+ * The contact ID (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String id;
+
+ /**
+ * The contact email address (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String email;
+
+ /**
+ * Constructs a new ListContactSegmentsOptions using the builder.
+ *
+ * @param builder The builder to construct from.
+ */
+ private ListContactSegmentsOptions(Builder builder) {
+ this.id = builder.id;
+ this.email = builder.email;
+ }
+
+ /**
+ * Gets the contact ID.
+ *
+ * @return The contact ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the contact email.
+ *
+ * @return The contact email.
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Creates a new Builder for constructing ListContactSegmentsOptions.
+ *
+ * @return A new Builder instance.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder class for constructing ListContactSegmentsOptions instances.
+ */
+ public static class Builder {
+ private String id;
+ private String email;
+
+ /**
+ * Sets the contact ID.
+ *
+ * @param id The contact ID.
+ * @return This builder instance.
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Sets the contact email.
+ *
+ * @param email The contact email.
+ * @return This builder instance.
+ */
+ public Builder email(String email) {
+ this.email = email;
+ return this;
+ }
+
+ /**
+ * Builds the ListContactSegmentsOptions instance.
+ *
+ * @return A new ListContactSegmentsOptions instance.
+ */
+ public ListContactSegmentsOptions build() {
+ return new ListContactSegmentsOptions(this);
+ }
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/ListContactSegmentsResponseSuccess.java b/src/main/java/com/resend/services/contacts/model/ListContactSegmentsResponseSuccess.java
new file mode 100644
index 0000000..c00058c
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/ListContactSegmentsResponseSuccess.java
@@ -0,0 +1,102 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+/**
+ * Represents the successful response from listing segments a contact belongs to.
+ */
+public class ListContactSegmentsResponseSuccess {
+
+ /**
+ * The object type.
+ */
+ @JsonProperty("object")
+ private String object;
+
+ /**
+ * The list of segments.
+ */
+ @JsonProperty("data")
+ private List data;
+
+ /**
+ * Indicates whether there are more segments to retrieve.
+ */
+ @JsonProperty("has_more")
+ private Boolean hasMore;
+
+ /**
+ * Default constructor.
+ */
+ public ListContactSegmentsResponseSuccess() {
+ }
+
+ /**
+ * Constructor with all fields.
+ *
+ * @param object The object type.
+ * @param data The list of segments.
+ * @param hasMore Whether there are more segments to retrieve.
+ */
+ public ListContactSegmentsResponseSuccess(String object, List data, Boolean hasMore) {
+ this.object = object;
+ this.data = data;
+ this.hasMore = hasMore;
+ }
+
+ /**
+ * Gets the object type.
+ *
+ * @return The object type.
+ */
+ public String getObject() {
+ return object;
+ }
+
+ /**
+ * Sets the object type.
+ *
+ * @param object The object type.
+ */
+ public void setObject(String object) {
+ this.object = object;
+ }
+
+ /**
+ * Gets the list of segments.
+ *
+ * @return The list of segments.
+ */
+ public List getData() {
+ return data;
+ }
+
+ /**
+ * Sets the list of segments.
+ *
+ * @param data The list of segments.
+ */
+ public void setData(List data) {
+ this.data = data;
+ }
+
+ /**
+ * Gets whether there are more segments to retrieve.
+ *
+ * @return True if there are more segments, false otherwise.
+ */
+ public Boolean getHasMore() {
+ return hasMore;
+ }
+
+ /**
+ * Sets whether there are more segments to retrieve.
+ *
+ * @param hasMore True if there are more segments, false otherwise.
+ */
+ public void setHasMore(Boolean hasMore) {
+ this.hasMore = hasMore;
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentOptions.java b/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentOptions.java
new file mode 100644
index 0000000..a44f923
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentOptions.java
@@ -0,0 +1,125 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Represents the options for removing a contact from a segment.
+ */
+public class RemoveContactFromSegmentOptions {
+
+ /**
+ * The contact ID (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String id;
+
+ /**
+ * The contact email address (either id or email must be provided, but not both).
+ */
+ @JsonIgnore
+ private String email;
+
+ /**
+ * The segment ID to remove the contact from (required).
+ */
+ @JsonIgnore
+ private String segmentId;
+
+ /**
+ * Constructs a new RemoveContactFromSegmentOptions using the builder.
+ *
+ * @param builder The builder to construct from.
+ */
+ private RemoveContactFromSegmentOptions(Builder builder) {
+ this.id = builder.id;
+ this.email = builder.email;
+ this.segmentId = builder.segmentId;
+ }
+
+ /**
+ * Gets the contact ID.
+ *
+ * @return The contact ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the contact email.
+ *
+ * @return The contact email.
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * Gets the segment ID.
+ *
+ * @return The segment ID.
+ */
+ public String getSegmentId() {
+ return segmentId;
+ }
+
+ /**
+ * Creates a new Builder for constructing RemoveContactFromSegmentOptions.
+ *
+ * @return A new Builder instance.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder class for constructing RemoveContactFromSegmentOptions instances.
+ */
+ public static class Builder {
+ private String id;
+ private String email;
+ private String segmentId;
+
+ /**
+ * Sets the contact ID.
+ *
+ * @param id The contact ID.
+ * @return This builder instance.
+ */
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ /**
+ * Sets the contact email.
+ *
+ * @param email The contact email.
+ * @return This builder instance.
+ */
+ public Builder email(String email) {
+ this.email = email;
+ return this;
+ }
+
+ /**
+ * Sets the segment ID.
+ *
+ * @param segmentId The segment ID.
+ * @return This builder instance.
+ */
+ public Builder segmentId(String segmentId) {
+ this.segmentId = segmentId;
+ return this;
+ }
+
+ /**
+ * Builds the RemoveContactFromSegmentOptions instance.
+ *
+ * @return A new RemoveContactFromSegmentOptions instance.
+ */
+ public RemoveContactFromSegmentOptions build() {
+ return new RemoveContactFromSegmentOptions(this);
+ }
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentResponseSuccess.java b/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentResponseSuccess.java
new file mode 100644
index 0000000..41a48cb
--- /dev/null
+++ b/src/main/java/com/resend/services/contacts/model/RemoveContactFromSegmentResponseSuccess.java
@@ -0,0 +1,57 @@
+package com.resend.services.contacts.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Represents the successful response from removing a contact from a segment.
+ */
+public class RemoveContactFromSegmentResponseSuccess {
+
+ /**
+ * The segment ID.
+ */
+ @JsonProperty("id")
+ private String id;
+
+ /**
+ * Indicates whether the contact was successfully removed from the segment.
+ */
+ @JsonProperty("deleted")
+ private Boolean deleted;
+
+ /**
+ * Gets the segment ID.
+ *
+ * @return The segment ID.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the segment ID.
+ *
+ * @param id The segment ID.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the deleted status.
+ *
+ * @return True if the contact was successfully removed from the segment.
+ */
+ public Boolean getDeleted() {
+ return deleted;
+ }
+
+ /**
+ * Sets the deleted status.
+ *
+ * @param deleted True if the contact was successfully removed from the segment.
+ */
+ public void setDeleted(Boolean deleted) {
+ this.deleted = deleted;
+ }
+}
diff --git a/src/main/java/com/resend/services/contacts/model/UpdateContactOptions.java b/src/main/java/com/resend/services/contacts/model/UpdateContactOptions.java
index 8d36761..8985a16 100644
--- a/src/main/java/com/resend/services/contacts/model/UpdateContactOptions.java
+++ b/src/main/java/com/resend/services/contacts/model/UpdateContactOptions.java
@@ -1,10 +1,15 @@
package com.resend.services.contacts.model;
+import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
- * Represents a request to update a contact.
+ * Represents a request to update a global contact.
+ *
+ * Note: This class is for updating global contacts only.
+ * Segment-related fields are ignored.
*/
+@JsonInclude(JsonInclude.Include.NON_NULL)
public class UpdateContactOptions {
@JsonProperty("id")
@@ -18,6 +23,7 @@ public class UpdateContactOptions {
private final String audienceId;
@JsonProperty("segment_id")
+ @Deprecated
private final String segmentId;
@JsonProperty("unsubscribed")
@@ -59,7 +65,9 @@ public String getAudienceId() {
* Get the segment ID of the contact.
*
* @return The segment ID of the contact.
+ * @deprecated This field is ignored when updating global contacts.
*/
+ @Deprecated
public String getSegmentId() {
return segmentId;
}
@@ -148,7 +156,9 @@ public Builder audienceId(String audienceId) {
*
* @param segmentId The segment ID of the contact.
* @return The builder instance.
+ * @deprecated This field is ignored when updating global contacts.
*/
+ @Deprecated
public Builder segmentId(String segmentId) {
this.segmentId = segmentId;
return this;
diff --git a/src/test/java/com/resend/services/contacts/ContactSegmentsTest.java b/src/test/java/com/resend/services/contacts/ContactSegmentsTest.java
new file mode 100644
index 0000000..69a56ee
--- /dev/null
+++ b/src/test/java/com/resend/services/contacts/ContactSegmentsTest.java
@@ -0,0 +1,145 @@
+package com.resend.services.contacts;
+
+import com.resend.core.exception.ResendException;
+import com.resend.core.net.ListParams;
+import com.resend.services.contacts.model.*;
+import com.resend.services.util.ContactsUtil;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.*;
+
+public class ContactSegmentsTest {
+
+ @Mock
+ private ContactSegments contactSegments;
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+ contactSegments = mock(ContactSegments.class);
+ }
+
+ @Test
+ public void testAddContactToSegmentById_Success() throws ResendException {
+ AddContactToSegmentOptions options = ContactsUtil.createAddContactToSegmentOptions();
+ AddContactToSegmentResponseSuccess expectedResponse = ContactsUtil.addContactToSegmentResponseSuccess();
+
+ when(contactSegments.add(options))
+ .thenReturn(expectedResponse);
+
+ AddContactToSegmentResponseSuccess res = contactSegments.add(options);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getId(), res.getId());
+ verify(contactSegments, times(1)).add(options);
+ }
+
+ @Test
+ public void testAddContactToSegmentByEmail_Success() throws ResendException {
+ AddContactToSegmentOptions options = AddContactToSegmentOptions.builder()
+ .email("steve.wozniak@gmail.com")
+ .segmentId("78261eea-8f8b-4381-83c6-79fa7120f1cf")
+ .build();
+ AddContactToSegmentResponseSuccess expectedResponse = ContactsUtil.addContactToSegmentResponseSuccess();
+
+ when(contactSegments.add(options))
+ .thenReturn(expectedResponse);
+
+ AddContactToSegmentResponseSuccess res = contactSegments.add(options);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getId(), res.getId());
+ verify(contactSegments, times(1)).add(options);
+ }
+
+ @Test
+ public void testRemoveContactFromSegmentById_Success() throws ResendException {
+ RemoveContactFromSegmentOptions options = ContactsUtil.createRemoveContactFromSegmentOptions();
+ RemoveContactFromSegmentResponseSuccess expectedResponse = ContactsUtil.removeContactFromSegmentResponseSuccess();
+
+ when(contactSegments.remove(options))
+ .thenReturn(expectedResponse);
+
+ RemoveContactFromSegmentResponseSuccess res = contactSegments.remove(options);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getId(), res.getId());
+ assertEquals(expectedResponse.getDeleted(), res.getDeleted());
+ verify(contactSegments, times(1)).remove(options);
+ }
+
+ @Test
+ public void testRemoveContactFromSegmentByEmail_Success() throws ResendException {
+ RemoveContactFromSegmentOptions options = RemoveContactFromSegmentOptions.builder()
+ .email("steve.wozniak@gmail.com")
+ .segmentId("78261eea-8f8b-4381-83c6-79fa7120f1cf")
+ .build();
+ RemoveContactFromSegmentResponseSuccess expectedResponse = ContactsUtil.removeContactFromSegmentResponseSuccess();
+
+ when(contactSegments.remove(options))
+ .thenReturn(expectedResponse);
+
+ RemoveContactFromSegmentResponseSuccess res = contactSegments.remove(options);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getId(), res.getId());
+ assertEquals(expectedResponse.getDeleted(), res.getDeleted());
+ verify(contactSegments, times(1)).remove(options);
+ }
+
+ @Test
+ public void testListContactSegmentsById_Success() throws ResendException {
+ String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
+ ListContactSegmentsResponseSuccess expectedResponse = ContactsUtil.listContactSegmentsResponseSuccess();
+
+ when(contactSegments.list(contactId))
+ .thenReturn(expectedResponse);
+
+ ListContactSegmentsResponseSuccess res = contactSegments.list(contactId);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactSegments, times(1)).list(contactId);
+ }
+
+ @Test
+ public void testListContactSegmentsByEmail_Success() throws ResendException {
+ String contactEmail = "steve.wozniak@gmail.com";
+ ListContactSegmentsResponseSuccess expectedResponse = ContactsUtil.listContactSegmentsResponseSuccess();
+
+ when(contactSegments.list(contactEmail))
+ .thenReturn(expectedResponse);
+
+ ListContactSegmentsResponseSuccess res = contactSegments.list(contactEmail);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactSegments, times(1)).list(contactEmail);
+ }
+
+ @Test
+ public void testListContactSegmentsWithPagination_Success() throws ResendException {
+ String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
+ ListParams params = ListParams.builder()
+ .limit(10)
+ .build();
+ ListContactSegmentsResponseSuccess expectedResponse = ContactsUtil.listContactSegmentsResponseSuccess();
+
+ when(contactSegments.list(contactId, params))
+ .thenReturn(expectedResponse);
+
+ ListContactSegmentsResponseSuccess res = contactSegments.list(contactId, params);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactSegments, times(1)).list(contactId, params);
+ }
+}
diff --git a/src/test/java/com/resend/services/contacts/ContactTopicsTest.java b/src/test/java/com/resend/services/contacts/ContactTopicsTest.java
new file mode 100644
index 0000000..8dda8e1
--- /dev/null
+++ b/src/test/java/com/resend/services/contacts/ContactTopicsTest.java
@@ -0,0 +1,94 @@
+package com.resend.services.contacts;
+
+import com.resend.core.exception.ResendException;
+import com.resend.core.net.ListParams;
+import com.resend.services.contacts.model.ListContactTopicsResponse;
+import com.resend.services.contacts.model.UpdateContactTopicsOptions;
+import com.resend.services.contacts.model.UpdateContactTopicsResponse;
+import com.resend.services.util.ContactsUtil;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.*;
+
+public class ContactTopicsTest {
+
+ @Mock
+ private ContactTopics contactTopics;
+
+ @BeforeEach
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+ contactTopics = mock(ContactTopics.class);
+ }
+
+ @Test
+ public void testListTopicsById_Success() throws ResendException {
+ String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
+ ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
+
+ when(contactTopics.list(contactId))
+ .thenReturn(expectedResponse);
+
+ ListContactTopicsResponse res = contactTopics.list(contactId);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactTopics, times(1)).list(contactId);
+ }
+
+ @Test
+ public void testListTopicsByEmail_Success() throws ResendException {
+ String contactEmail = "steve.wozniak@gmail.com";
+ ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
+
+ when(contactTopics.list(contactEmail))
+ .thenReturn(expectedResponse);
+
+ ListContactTopicsResponse res = contactTopics.list(contactEmail);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactTopics, times(1)).list(contactEmail);
+ }
+
+ @Test
+ public void testListTopicsWithPagination_Success() throws ResendException {
+ String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
+ ListParams params = ListParams.builder()
+ .limit(10)
+ .build();
+ ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
+
+ when(contactTopics.list(contactId, params))
+ .thenReturn(expectedResponse);
+
+ ListContactTopicsResponse res = contactTopics.list(contactId, params);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getData().size(), res.getData().size());
+ assertEquals(expectedResponse.getObject(), res.getObject());
+ verify(contactTopics, times(1)).list(contactId, params);
+ }
+
+ @Test
+ public void testUpdateTopics_Success() throws ResendException {
+ UpdateContactTopicsOptions options = ContactsUtil.createUpdateTopicsOptions();
+ UpdateContactTopicsResponse expectedResponse = ContactsUtil.updateContactTopicsResponse();
+
+ when(contactTopics.update(options))
+ .thenReturn(expectedResponse);
+
+ UpdateContactTopicsResponse res = contactTopics.update(options);
+
+ assertNotNull(res);
+ assertEquals(expectedResponse.getId(), res.getId());
+ verify(contactTopics, times(1)).update(options);
+ }
+}
diff --git a/src/test/java/com/resend/services/contacts/ContactsTest.java b/src/test/java/com/resend/services/contacts/ContactsTest.java
index f4bbb97..c518d56 100644
--- a/src/test/java/com/resend/services/contacts/ContactsTest.java
+++ b/src/test/java/com/resend/services/contacts/ContactsTest.java
@@ -138,72 +138,6 @@ public void testGetContactByEmail_Success() throws ResendException {
verify(contacts, times(1)).get(params);
}
- @Test
- public void testGetTopicsById_Success() throws ResendException {
- String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
- ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
-
- when(contacts.getTopics(contactId))
- .thenReturn(expectedResponse);
-
- ListContactTopicsResponse res = contacts.getTopics(contactId);
-
- assertNotNull(res);
- assertEquals(expectedResponse.getData().size(), res.getData().size());
- assertEquals(expectedResponse.getObject(), res.getObject());
- verify(contacts, times(1)).getTopics(contactId);
- }
-
- @Test
- public void testGetTopicsByEmail_Success() throws ResendException {
- String contactEmail = "steve.wozniak@gmail.com";
- ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
-
- when(contacts.getTopics(contactEmail))
- .thenReturn(expectedResponse);
-
- ListContactTopicsResponse res = contacts.getTopics(contactEmail);
-
- assertNotNull(res);
- assertEquals(expectedResponse.getData().size(), res.getData().size());
- assertEquals(expectedResponse.getObject(), res.getObject());
- verify(contacts, times(1)).getTopics(contactEmail);
- }
-
- @Test
- public void testGetTopicsWithPagination_Success() throws ResendException {
- String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3";
- ListParams params = ListParams.builder()
- .limit(10)
- .build();
- ListContactTopicsResponse expectedResponse = ContactsUtil.createContactTopicsListResponse();
-
- when(contacts.getTopics(contactId, params))
- .thenReturn(expectedResponse);
-
- ListContactTopicsResponse res = contacts.getTopics(contactId, params);
-
- assertNotNull(res);
- assertEquals(expectedResponse.getData().size(), res.getData().size());
- assertEquals(expectedResponse.getObject(), res.getObject());
- verify(contacts, times(1)).getTopics(contactId, params);
- }
-
- @Test
- public void testUpdateTopics_Success() throws ResendException {
- UpdateContactTopicsOptions options = ContactsUtil.createUpdateTopicsOptions();
- UpdateContactTopicsResponse expectedResponse = ContactsUtil.updateContactTopicsResponse();
-
- when(contacts.updateTopics(options))
- .thenReturn(expectedResponse);
-
- UpdateContactTopicsResponse res = contacts.updateTopics(options);
-
- assertNotNull(res);
- assertEquals(expectedResponse.getId(), res.getId());
- verify(contacts, times(1)).updateTopics(options);
- }
-
// Global contacts tests (without segment ID)
@Test
diff --git a/src/test/java/com/resend/services/util/ContactsUtil.java b/src/test/java/com/resend/services/util/ContactsUtil.java
index 3fbe7b4..c8ea043 100644
--- a/src/test/java/com/resend/services/util/ContactsUtil.java
+++ b/src/test/java/com/resend/services/util/ContactsUtil.java
@@ -103,4 +103,51 @@ public static UpdateContactTopicsOptions createUpdateTopicsOptions() {
public static UpdateContactTopicsResponse updateContactTopicsResponse() {
return new UpdateContactTopicsResponse("e169aa45-1ecf-4183-9955-b1499d5701d3");
}
+
+ public static AddContactToSegmentOptions createAddContactToSegmentOptions() {
+ return AddContactToSegmentOptions.builder()
+ .id("e169aa45-1ecf-4183-9955-b1499d5701d3")
+ .segmentId("78261eea-8f8b-4381-83c6-79fa7120f1cf")
+ .build();
+ }
+
+ public static AddContactToSegmentResponseSuccess addContactToSegmentResponseSuccess() {
+ AddContactToSegmentResponseSuccess response = new AddContactToSegmentResponseSuccess();
+ response.setId("78261eea-8f8b-4381-83c6-79fa7120f1cf");
+ return response;
+ }
+
+ public static RemoveContactFromSegmentOptions createRemoveContactFromSegmentOptions() {
+ return RemoveContactFromSegmentOptions.builder()
+ .id("e169aa45-1ecf-4183-9955-b1499d5701d3")
+ .segmentId("78261eea-8f8b-4381-83c6-79fa7120f1cf")
+ .build();
+ }
+
+ public static RemoveContactFromSegmentResponseSuccess removeContactFromSegmentResponseSuccess() {
+ RemoveContactFromSegmentResponseSuccess response = new RemoveContactFromSegmentResponseSuccess();
+ response.setId("78261eea-8f8b-4381-83c6-79fa7120f1cf");
+ response.setDeleted(true);
+ return response;
+ }
+
+ public static ListContactSegmentsResponseSuccess listContactSegmentsResponseSuccess() {
+ List segments = new ArrayList<>();
+
+ ContactSegment seg1 = new ContactSegment(
+ "78261eea-8f8b-4381-83c6-79fa7120f1cf",
+ "Registered Users",
+ "2023-10-06T22:59:55.977Z"
+ );
+ ContactSegment seg2 = new ContactSegment(
+ "b9d24c8e-bf1c-5d4d-cf1d-470cbd97482f",
+ "Premium Users",
+ "2023-11-12T14:23:10.123Z"
+ );
+
+ segments.add(seg1);
+ segments.add(seg2);
+
+ return new ListContactSegmentsResponseSuccess("list", segments, false);
+ }
}