Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions resend/contacts/_contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,29 +250,34 @@ def update(cls, params: UpdateParams) -> UpdateContactResponse:

@classmethod
def list(
cls, audience_id: Optional[str] = None, params: Optional[ListParams] = None
cls,
audience_id: Optional[str] = None,
params: Optional[ListParams] = None,
segment_id: Optional[str] = None,
) -> ListResponse:
"""
List all contacts.
Can list either global contacts or audience-specific contacts.
Can list global contacts, audience-specific contacts, or segment contacts.
see more: https://resend.com/docs/api-reference/contacts/list-contacts

Args:
audience_id (Optional[str]): The audience ID. If not provided, lists all global contacts.
audience_id (Optional[str]): Deprecated. Use segment_id instead.
params (Optional[ListParams]): Optional pagination parameters
- limit: Number of contacts to retrieve (max 100, min 1).
If not provided, all contacts will be returned without pagination.
- after: ID after which to retrieve more contacts
- before: ID before which to retrieve more contacts
segment_id (Optional[str]): The segment ID. When provided, lists contacts
in the segment via GET /segments/{segment_id}/contacts.

Returns:
ListResponse: A list of contact objects
"""
if audience_id:
# Audience-specific contacts
if segment_id:
base_path = f"/segments/{segment_id}/contacts"
elif audience_id:
base_path = f"/audiences/{audience_id}/contacts"
else:
# Global contacts
base_path = "/contacts"

query_params = cast(Dict[Any, Any], params) if params else None
Expand Down Expand Up @@ -419,21 +424,28 @@ async def update_async(cls, params: UpdateParams) -> UpdateContactResponse:

@classmethod
async def list_async(
cls, audience_id: Optional[str] = None, params: Optional[ListParams] = None
cls,
audience_id: Optional[str] = None,
params: Optional[ListParams] = None,
segment_id: Optional[str] = None,
) -> ListResponse:
"""
List all contacts (async).
Can list either global contacts or audience-specific contacts.
Can list global contacts, audience-specific contacts, or segment contacts.
see more: https://resend.com/docs/api-reference/contacts/list-contacts

Args:
audience_id (Optional[str]): The audience ID. If not provided, lists all global contacts.
audience_id (Optional[str]): Deprecated. Use segment_id instead.
params (Optional[ListParams]): Optional pagination parameters
segment_id (Optional[str]): The segment ID. When provided, lists contacts
in the segment via GET /segments/{segment_id}/contacts.

Returns:
ListResponse: A list of contact objects
"""
if audience_id:
if segment_id:
base_path = f"/segments/{segment_id}/contacts"
elif audience_id:
base_path = f"/audiences/{audience_id}/contacts"
else:
base_path = "/contacts"
Expand Down
35 changes: 35 additions & 0 deletions tests/contacts_async_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,38 @@ async def test_should_list_contacts_async_raise_exception_when_no_content(
_ = await resend.Contacts.list_async(
audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8"
)

async def test_contacts_list_async_by_segment_id(self) -> None:
self.set_mock_json(
{
"object": "list",
"has_more": False,
"data": [
{
"id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
"email": "steve.wozniak@gmail.com",
"first_name": "Steve",
"last_name": "Wozniak",
"created_at": "2023-10-06T23:47:56.678Z",
"unsubscribed": False,
}
],
}
)

contacts: resend.Contacts.ListResponse = await resend.Contacts.list_async(
segment_id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
)
assert contacts["object"] == "list"
assert contacts["has_more"] is False
assert contacts["data"][0]["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3"
assert contacts["data"][0]["email"] == "steve.wozniak@gmail.com"

async def test_should_list_contacts_async_by_segment_raise_exception_when_no_content(
self,
) -> None:
self.set_mock_json(None)
with pytest.raises(NoContentError):
_ = await resend.Contacts.list_async(
segment_id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
)
59 changes: 59 additions & 0 deletions tests/contacts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,65 @@ def test_contacts_list_global(self) -> None:
assert contacts["data"][0]["id"] == "global-1"
assert contacts["data"][1]["id"] == "global-2"

def test_contacts_list_by_segment_id(self) -> None:
self.set_mock_json(
{
"object": "list",
"has_more": False,
"data": [
{
"id": "e169aa45-1ecf-4183-9955-b1499d5701d3",
"email": "steve.wozniak@gmail.com",
"first_name": "Steve",
"last_name": "Wozniak",
"created_at": "2023-10-06T23:47:56.678Z",
"unsubscribed": False,
}
],
}
)

contacts: resend.Contacts.ListResponse = resend.Contacts.list(
segment_id="78261eea-8f8b-4381-83c6-79fa7120f1cf"
)
assert contacts["object"] == "list"
assert contacts["has_more"] is False
assert contacts["data"][0]["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3"
assert contacts["data"][0]["email"] == "steve.wozniak@gmail.com"

def test_contacts_list_by_segment_id_with_pagination(self) -> None:
self.set_mock_json(
{
"object": "list",
"has_more": True,
"data": [
{
"id": "contact-1",
"email": "contact1@example.com",
"first_name": "Contact",
"last_name": "One",
"created_at": "2023-10-06T23:47:56.678Z",
"unsubscribed": False,
}
],
}
)

params: resend.Contacts.ListParams = {"limit": 10, "after": "previous-id"}
contacts: resend.Contacts.ListResponse = resend.Contacts.list(
segment_id="78261eea-8f8b-4381-83c6-79fa7120f1cf", params=params
)
assert contacts["object"] == "list"
assert contacts["has_more"] is True
assert len(contacts["data"]) == 1

def test_should_list_contacts_by_segment_raise_exception_when_no_content(
self,
) -> None:
self.set_mock_json(None)
with self.assertRaises(NoContentError):
_ = resend.Contacts.list(segment_id="78261eea-8f8b-4381-83c6-79fa7120f1cf")

def test_contacts_remove_global_by_id(self) -> None:
self.set_mock_json(
{
Expand Down
Loading