From 5ed2b1eabd03670e3ab86189fe327ea2727e34f7 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 16:55:43 -0300 Subject: [PATCH 1/8] feat: pagination helper + api keys list pagination support --- examples/api_keys.py | 12 +++++ resend/api_keys/_api_keys.py | 45 ++++++++++++++++-- resend/pagination_helper.py | 34 ++++++++++++++ tests/api_keys_test.py | 60 ++++++++++++++++++++++++ tests/pagination_helper_test.py | 82 +++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 resend/pagination_helper.py create mode 100644 tests/pagination_helper_test.py diff --git a/examples/api_keys.py b/examples/api_keys.py index ae44901..eb5b330 100644 --- a/examples/api_keys.py +++ b/examples/api_keys.py @@ -22,5 +22,17 @@ print(key["name"]) print(key["created_at"]) +print("\n--- Using pagination parameters ---") +if keys["data"]: + paginated_params: resend.ApiKeys.ListParams = { + "limit": 8, + "after": keys["data"][0]["id"] + } + paginated_keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=paginated_params) + print(f"Retrieved {len(paginated_keys['data'])} keys with pagination") + print(f"Has more keys: {paginated_keys['has_more']}") +else: + print("No keys available for pagination example") + if len(keys["data"]) > 0: resend.ApiKeys.remove(api_key_id=keys["data"][0]["id"]) diff --git a/resend/api_keys/_api_keys.py b/resend/api_keys/_api_keys.py index 11954f9..843cf8c 100644 --- a/resend/api_keys/_api_keys.py +++ b/resend/api_keys/_api_keys.py @@ -1,25 +1,36 @@ -from typing import Any, Dict, List, cast +from typing import Any, Dict, List, Optional, cast from typing_extensions import NotRequired, TypedDict from resend import request from resend.api_keys._api_key import ApiKey +from resend.pagination_helper import PaginationHelper class ApiKeys: class ListResponse(TypedDict): """ - ListResponse type that wraps a list of API key objects + ListResponse type that wraps a list of API key objects with pagination metadata Attributes: + object (str): The object type, always "list" data (List[ApiKey]): A list of API key objects + has_more (bool): Whether there are more results available """ + object: str + """ + The object type, always "list" + """ data: List[ApiKey] """ A list of API key objects """ + has_more: bool + """ + Whether there are more results available for pagination + """ class CreateApiKeyResponse(TypedDict): """ @@ -39,6 +50,24 @@ class CreateApiKeyResponse(TypedDict): The token of the created API key """ + class ListParams(TypedDict): + limit: NotRequired[int] + """ + Number of API keys to retrieve. Maximum is 100, and minimum is 1. + """ + after: NotRequired[str] + """ + The ID after which we'll retrieve more API keys (for pagination). + This ID will not be included in the returned list. + Cannot be used with the before parameter. + """ + before: NotRequired[str] + """ + The ID before which we'll retrieve more API keys (for pagination). + This ID will not be included in the returned list. + Cannot be used with the after parameter. + """ + class CreateParams(TypedDict): name: str """ @@ -75,15 +104,23 @@ def create(cls, params: CreateParams) -> CreateApiKeyResponse: return resp @classmethod - def list(cls) -> ListResponse: + def list(cls, params: Optional[ListParams] = None) -> ListResponse: """ Retrieve a list of API keys for the authenticated user. see more: https://resend.com/docs/api-reference/api-keys/list-api-keys + Args: + params (Optional[ListParams]): Optional pagination parameters + - limit: Number of API keys to retrieve (max 100, min 1) + - after: ID after which to retrieve more API keys + - before: ID before which to retrieve more API keys + Returns: ListResponse: A list of API key objects """ - path = "/api-keys" + base_path = "/api-keys" + query_params = cast(Dict[Any, Any], params) if params else None + path = PaginationHelper.build_paginated_path(base_path, query_params) resp = request.Request[ApiKeys.ListResponse]( path=path, params={}, verb="get" ).perform_with_content() diff --git a/resend/pagination_helper.py b/resend/pagination_helper.py new file mode 100644 index 0000000..ac79227 --- /dev/null +++ b/resend/pagination_helper.py @@ -0,0 +1,34 @@ +from typing import Any, Dict, Optional +from urllib.parse import urlencode + + +class PaginationHelper: + """Helper class for building paginated URLs with query parameters.""" + + @staticmethod + def build_paginated_path(path: str, params: Optional[Dict[str, Any]] = None) -> str: + """ + Build a path with query parameters for pagination. + + Args: + path: The base API path (e.g., "/api-keys") + params: Optional dictionary of query parameters + + Returns: + The path with query parameters appended if any valid params exist + """ + if not params: + return path + + # Filter out None values + query_params = {k: v for k, v in params.items() if v is not None} + + if not query_params: + return path + + # Build the query string + query_string = urlencode(query_params) + + # Append to path with proper separator + separator = "&" if "?" in path else "?" + return f"{path}{separator}{query_string}" diff --git a/tests/api_keys_test.py b/tests/api_keys_test.py index f643cca..d6c224b 100644 --- a/tests/api_keys_test.py +++ b/tests/api_keys_test.py @@ -31,6 +31,8 @@ def test_should_create_api_key_raise_exception_when_no_content(self) -> None: def test_api_keys_list(self) -> None: self.set_mock_json( { + "object": "list", + "has_more": False, "data": [ { "id": "91f3200a-df72-4654-b0cd-f202395f5354", @@ -42,6 +44,8 @@ def test_api_keys_list(self) -> None: ) keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list() + assert keys["object"] == "list" + assert keys["has_more"] is False for key in keys["data"]: assert key["id"] == "91f3200a-df72-4654-b0cd-f202395f5354" assert key["name"] == "Production" @@ -52,6 +56,62 @@ def test_should_list_api_key_raise_exception_when_no_content(self) -> None: with self.assertRaises(NoContentError): _ = resend.ApiKeys.list() + def test_api_keys_list_with_pagination_params(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": True, + "data": [ + { + "id": "test-key-1", + "name": "Test Key 1", + "created_at": "2023-04-08T00:11:13.110779+00:00", + }, + { + "id": "test-key-2", + "name": "Test Key 2", + "created_at": "2023-04-09T00:11:13.110779+00:00", + } + ] + } + ) + + params: resend.ApiKeys.ListParams = { + "limit": 10, + "after": "previous-key-id" + } + keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=params) + assert keys["object"] == "list" + assert keys["has_more"] is True + assert len(keys["data"]) == 2 + assert keys["data"][0]["id"] == "test-key-1" + assert keys["data"][1]["id"] == "test-key-2" + + def test_api_keys_list_with_before_param(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": False, + "data": [ + { + "id": "test-key-3", + "name": "Test Key 3", + "created_at": "2023-04-07T00:11:13.110779+00:00", + } + ] + } + ) + + params: resend.ApiKeys.ListParams = { + "limit": 5, + "before": "later-key-id" + } + keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=params) + assert keys["object"] == "list" + assert keys["has_more"] is False + assert len(keys["data"]) == 1 + assert keys["data"][0]["id"] == "test-key-3" + def test_api_keys_remove(self) -> None: self.set_mock_text("") diff --git a/tests/pagination_helper_test.py b/tests/pagination_helper_test.py new file mode 100644 index 0000000..0713711 --- /dev/null +++ b/tests/pagination_helper_test.py @@ -0,0 +1,82 @@ +import unittest + +from resend.pagination_helper import PaginationHelper + + +class TestPaginationHelper(unittest.TestCase): + def test_build_paginated_path_with_no_params(self) -> None: + """Test that path is returned unchanged when no params are provided.""" + path = "/api-keys" + result = PaginationHelper.build_paginated_path(path) + assert result == "/api-keys" + + def test_build_paginated_path_with_none_params(self) -> None: + """Test that path is returned unchanged when params is None.""" + path = "/api-keys" + result = PaginationHelper.build_paginated_path(path, None) + assert result == "/api-keys" + + def test_build_paginated_path_with_empty_params(self) -> None: + """Test that path is returned unchanged when params dict is empty.""" + path = "/api-keys" + result = PaginationHelper.build_paginated_path(path, {}) + assert result == "/api-keys" + + def test_build_paginated_path_with_single_param(self) -> None: + """Test building path with a single query parameter.""" + path = "/api-keys" + params = {"limit": 10} + result = PaginationHelper.build_paginated_path(path, params) + assert result == "/api-keys?limit=10" + + def test_build_paginated_path_with_multiple_params(self) -> None: + """Test building path with multiple query parameters.""" + path = "/api-keys" + params = {"limit": 10, "after": "key-123"} + result = PaginationHelper.build_paginated_path(path, params) + # Check both possible orderings since dict ordering may vary + assert result in [ + "/api-keys?limit=10&after=key-123", + "/api-keys?after=key-123&limit=10", + ] + + def test_build_paginated_path_filters_none_values(self) -> None: + """Test that None values are filtered out from params.""" + path = "/api-keys" + params = {"limit": 10, "after": None, "before": "key-456"} + result = PaginationHelper.build_paginated_path(path, params) + # Should not include 'after' since it's None + assert "after" not in result + assert "limit=10" in result + assert "before=key-456" in result + + def test_build_paginated_path_with_all_none_values(self) -> None: + """Test that path is unchanged when all param values are None.""" + path = "/api-keys" + params = {"limit": None, "after": None, "before": None} + result = PaginationHelper.build_paginated_path(path, params) + assert result == "/api-keys" + + def test_build_paginated_path_with_existing_query_string(self) -> None: + """Test appending params to a path that already has a query string.""" + path = "/api-keys?status=active" + params = {"limit": 5} + result = PaginationHelper.build_paginated_path(path, params) + assert result == "/api-keys?status=active&limit=5" + + def test_build_paginated_path_with_special_characters(self) -> None: + """Test that special characters in params are properly URL encoded.""" + path = "/api-keys" + params = {"after": "key with spaces", "tag": "test&value"} + result = PaginationHelper.build_paginated_path(path, params) + # Check URL encoding + assert "key+with+spaces" in result or "key%20with%20spaces" in result + assert "test%26value" in result + + def test_build_paginated_path_with_integer_values(self) -> None: + """Test that integer values are properly converted to strings.""" + path = "/audiences" + params = {"limit": 100, "offset": 0} + result = PaginationHelper.build_paginated_path(path, params) + assert "limit=100" in result + assert "offset=0" in result \ No newline at end of file From d3a8c70fe58a6b6e09070cff3aca7a1c1c2c6846 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 17:03:43 -0300 Subject: [PATCH 2/8] feat: audiencest list method pagination support --- examples/audiences.py | 13 ++++++++ resend/audiences/_audiences.py | 46 ++++++++++++++++++++++---- tests/audiences_test.py | 59 ++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/examples/audiences.py b/examples/audiences.py index 7647bb2..afeeba0 100644 --- a/examples/audiences.py +++ b/examples/audiences.py @@ -21,6 +21,19 @@ audiences: resend.Audiences.ListResponse = resend.Audiences.list() print("List of audiences:", [a["id"] for a in audiences["data"]]) +print(f"Has more audiences: {audiences['has_more']}") + +print("\n--- Using pagination parameters ---") +if audiences["data"]: + paginated_params: resend.Audiences.ListParams = { + "limit": 5, + "after": audiences["data"][0]["id"] + } + paginated_audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=paginated_params) + print(f"Retrieved {len(paginated_audiences['data'])} audiences with pagination") + print(f"Has more audiences: {paginated_audiences['has_more']}") +else: + print("No audiences available for pagination example") rmed: resend.Audiences.RemoveAudienceResponse = resend.Audiences.remove( id=audience["id"] diff --git a/resend/audiences/_audiences.py b/resend/audiences/_audiences.py index a07925c..bc3a669 100644 --- a/resend/audiences/_audiences.py +++ b/resend/audiences/_audiences.py @@ -1,8 +1,9 @@ -from typing import Any, Dict, List, cast +from typing import Any, Dict, List, Optional, cast -from typing_extensions import TypedDict +from typing_extensions import NotRequired, TypedDict from resend import request +from resend.pagination_helper import PaginationHelper from ._audience import Audience @@ -32,23 +33,46 @@ class RemoveAudienceResponse(TypedDict): Whether the audience was deleted """ + class ListParams(TypedDict): + limit: NotRequired[int] + """ + Number of audiences to retrieve. Maximum is 100, and minimum is 1. + """ + after: NotRequired[str] + """ + The ID after which we'll retrieve more audiences (for pagination). + This ID will not be included in the returned list. + Cannot be used with the before parameter. + """ + before: NotRequired[str] + """ + The ID before which we'll retrieve more audiences (for pagination). + This ID will not be included in the returned list. + Cannot be used with the after parameter. + """ + class ListResponse(TypedDict): """ - ListResponse type that wraps a list of audience objects + ListResponse type that wraps a list of audience objects with pagination metadata Attributes: - object (str): The object type, "list" + object (str): The object type, always "list" data (List[Audience]): A list of audience objects + has_more (bool): Whether there are more results available """ object: str """ - The object type, "list" + The object type, always "list" """ data: List[Audience] """ A list of audience objects """ + has_more: bool + """ + Whether there are more results available for pagination + """ class CreateAudienceResponse(TypedDict): """ @@ -99,15 +123,23 @@ def create(cls, params: CreateParams) -> CreateAudienceResponse: return resp @classmethod - def list(cls) -> ListResponse: + def list(cls, params: Optional[ListParams] = None) -> ListResponse: """ Retrieve a list of audiences. see more: https://resend.com/docs/api-reference/audiences/list-audiences + Args: + params (Optional[ListParams]): Optional pagination parameters + - limit: Number of audiences to retrieve (max 100, min 1) + - after: ID after which to retrieve more audiences + - before: ID before which to retrieve more audiences + Returns: ListResponse: A list of audience objects """ - path = "/audiences/" + base_path = "/audiences" + query_params = cast(Dict[Any, Any], params) if params else None + path = PaginationHelper.build_paginated_path(base_path, query_params) resp = request.Request[Audiences.ListResponse]( path=path, params={}, verb="get" ).perform_with_content() diff --git a/tests/audiences_test.py b/tests/audiences_test.py index f7eaf79..d251047 100644 --- a/tests/audiences_test.py +++ b/tests/audiences_test.py @@ -75,6 +75,7 @@ def test_audiences_list(self) -> None: self.set_mock_json( { "object": "list", + "has_more": False, "data": [ { "id": "78261eea-8f8b-4381-83c6-79fa7120f1cf", @@ -86,6 +87,8 @@ def test_audiences_list(self) -> None: ) audiences: resend.Audiences.ListResponse = resend.Audiences.list() + assert audiences["object"] == "list" + assert audiences["has_more"] is False assert audiences["data"][0]["id"] == "78261eea-8f8b-4381-83c6-79fa7120f1cf" assert audiences["data"][0]["name"] == "Registered Users" @@ -93,3 +96,59 @@ def test_should_list_audiences_raise_exception_when_no_content(self) -> None: self.set_mock_json(None) with self.assertRaises(NoContentError): _ = resend.Audiences.list() + + def test_audiences_list_with_pagination_params(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": True, + "data": [ + { + "id": "audience-1", + "name": "First Audience", + "created_at": "2023-10-06T22:59:55.977Z", + }, + { + "id": "audience-2", + "name": "Second Audience", + "created_at": "2023-10-07T22:59:55.977Z", + } + ], + } + ) + + params: resend.Audiences.ListParams = { + "limit": 10, + "after": "previous-audience-id" + } + audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=params) + assert audiences["object"] == "list" + assert audiences["has_more"] is True + assert len(audiences["data"]) == 2 + assert audiences["data"][0]["id"] == "audience-1" + assert audiences["data"][1]["id"] == "audience-2" + + def test_audiences_list_with_before_param(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": False, + "data": [ + { + "id": "audience-3", + "name": "Third Audience", + "created_at": "2023-10-05T22:59:55.977Z", + } + ], + } + ) + + params: resend.Audiences.ListParams = { + "limit": 5, + "before": "later-audience-id" + } + audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=params) + assert audiences["object"] == "list" + assert audiences["has_more"] is False + assert len(audiences["data"]) == 1 + assert audiences["data"][0]["id"] == "audience-3" From 63f16d4b7c5c3a4b024b0e5e9dbfba531bb189d8 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 17:13:09 -0300 Subject: [PATCH 3/8] feat: broadcasts list method pagination support --- examples/api_keys.py | 6 ++- examples/audiences.py | 6 ++- examples/broadcasts.py | 17 +++++++- resend/broadcasts/_broadcasts.py | 44 +++++++++++++++++--- tests/api_keys_test.py | 18 +++----- tests/audiences_test.py | 6 +-- tests/broadcasts_test.py | 71 ++++++++++++++++++++++++++++++++ tests/pagination_helper_test.py | 2 +- 8 files changed, 143 insertions(+), 27 deletions(-) diff --git a/examples/api_keys.py b/examples/api_keys.py index eb5b330..37a9af1 100644 --- a/examples/api_keys.py +++ b/examples/api_keys.py @@ -26,9 +26,11 @@ if keys["data"]: paginated_params: resend.ApiKeys.ListParams = { "limit": 8, - "after": keys["data"][0]["id"] + "after": keys["data"][0]["id"], } - paginated_keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=paginated_params) + paginated_keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list( + params=paginated_params + ) print(f"Retrieved {len(paginated_keys['data'])} keys with pagination") print(f"Has more keys: {paginated_keys['has_more']}") else: diff --git a/examples/audiences.py b/examples/audiences.py index afeeba0..5d002c3 100644 --- a/examples/audiences.py +++ b/examples/audiences.py @@ -27,9 +27,11 @@ if audiences["data"]: paginated_params: resend.Audiences.ListParams = { "limit": 5, - "after": audiences["data"][0]["id"] + "after": audiences["data"][0]["id"], } - paginated_audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=paginated_params) + paginated_audiences: resend.Audiences.ListResponse = resend.Audiences.list( + params=paginated_params + ) print(f"Retrieved {len(paginated_audiences['data'])} audiences with pagination") print(f"Has more audiences: {paginated_audiences['has_more']}") else: diff --git a/examples/broadcasts.py b/examples/broadcasts.py index bcd8d26..a730828 100644 --- a/examples/broadcasts.py +++ b/examples/broadcasts.py @@ -58,4 +58,19 @@ list_response: resend.Broadcasts.ListResponse = resend.Broadcasts.list() print("List of broadcasts !\n") -print(list_response) +print(f"Found {len(list_response['data'])} broadcasts") +print(f"Has more broadcasts: {list_response['has_more']}") + +print("\n--- Using pagination parameters ---") +if list_response["data"]: + paginated_params: resend.Broadcasts.ListParams = { + "limit": 3, + "after": list_response["data"][0]["id"], + } + paginated_broadcasts: resend.Broadcasts.ListResponse = resend.Broadcasts.list( + params=paginated_params + ) + print(f"Retrieved {len(paginated_broadcasts['data'])} broadcasts with pagination") + print(f"Has more broadcasts: {paginated_broadcasts['has_more']}") +else: + print("No broadcasts available for pagination example") diff --git a/resend/broadcasts/_broadcasts.py b/resend/broadcasts/_broadcasts.py index 284d4b7..92170a8 100644 --- a/resend/broadcasts/_broadcasts.py +++ b/resend/broadcasts/_broadcasts.py @@ -1,8 +1,9 @@ -from typing import Any, Dict, List, Union, cast +from typing import Any, Dict, List, Optional, Union, cast from typing_extensions import NotRequired, TypedDict from resend import request +from resend.pagination_helper import PaginationHelper from ._broadcast import Broadcast @@ -160,23 +161,46 @@ class SendResponse(CreateResponse): id (str): id of the created broadcast """ + class ListParams(TypedDict): + limit: NotRequired[int] + """ + Number of broadcasts to retrieve. Maximum is 100, and minimum is 1. + """ + after: NotRequired[str] + """ + The ID after which we'll retrieve more broadcasts (for pagination). + This ID will not be included in the returned list. + Cannot be used with the before parameter. + """ + before: NotRequired[str] + """ + The ID before which we'll retrieve more broadcasts (for pagination). + This ID will not be included in the returned list. + Cannot be used with the after parameter. + """ + class ListResponse(TypedDict): """ - ListResponse is the class that wraps the response of the list method. + ListResponse is the class that wraps the response of the list method with pagination metadata. Attributes: - object (str): object type: "list" + object (str): object type, always "list" data (List[Broadcast]): A list of broadcast objects + has_more (bool): Whether there are more results available """ object: str """ - object type: "list" + object type, always "list" """ data: List[Broadcast] """ A list of broadcast objects """ + has_more: bool + """ + Whether there are more results available for pagination + """ class RemoveResponse(TypedDict): """ @@ -259,15 +283,23 @@ def send(cls, params: SendParams) -> SendResponse: return resp @classmethod - def list(cls) -> ListResponse: + def list(cls, params: Optional[ListParams] = None) -> ListResponse: """ Retrieve a list of broadcasts. see more: https://resend.com/docs/api-reference/broadcasts/list-broadcasts + Args: + params (Optional[ListParams]): Optional pagination parameters + - limit: Number of broadcasts to retrieve (max 100, min 1) + - after: ID after which to retrieve more broadcasts + - before: ID before which to retrieve more broadcasts + Returns: ListResponse: A list of broadcast objects """ - path = "/broadcasts/" + base_path = "/broadcasts" + query_params = cast(Dict[Any, Any], params) if params else None + path = PaginationHelper.build_paginated_path(base_path, query_params) resp = request.Request[Broadcasts.ListResponse]( path=path, params={}, verb="get" ).perform_with_content() diff --git a/tests/api_keys_test.py b/tests/api_keys_test.py index d6c224b..3ad6d18 100644 --- a/tests/api_keys_test.py +++ b/tests/api_keys_test.py @@ -39,7 +39,7 @@ def test_api_keys_list(self) -> None: "name": "Production", "created_at": "2023-04-08T00:11:13.110779+00:00", } - ] + ], } ) @@ -71,15 +71,12 @@ def test_api_keys_list_with_pagination_params(self) -> None: "id": "test-key-2", "name": "Test Key 2", "created_at": "2023-04-09T00:11:13.110779+00:00", - } - ] + }, + ], } ) - params: resend.ApiKeys.ListParams = { - "limit": 10, - "after": "previous-key-id" - } + params: resend.ApiKeys.ListParams = {"limit": 10, "after": "previous-key-id"} keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=params) assert keys["object"] == "list" assert keys["has_more"] is True @@ -98,14 +95,11 @@ def test_api_keys_list_with_before_param(self) -> None: "name": "Test Key 3", "created_at": "2023-04-07T00:11:13.110779+00:00", } - ] + ], } ) - params: resend.ApiKeys.ListParams = { - "limit": 5, - "before": "later-key-id" - } + params: resend.ApiKeys.ListParams = {"limit": 5, "before": "later-key-id"} keys: resend.ApiKeys.ListResponse = resend.ApiKeys.list(params=params) assert keys["object"] == "list" assert keys["has_more"] is False diff --git a/tests/audiences_test.py b/tests/audiences_test.py index d251047..d05a355 100644 --- a/tests/audiences_test.py +++ b/tests/audiences_test.py @@ -112,14 +112,14 @@ def test_audiences_list_with_pagination_params(self) -> None: "id": "audience-2", "name": "Second Audience", "created_at": "2023-10-07T22:59:55.977Z", - } + }, ], } ) params: resend.Audiences.ListParams = { "limit": 10, - "after": "previous-audience-id" + "after": "previous-audience-id", } audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=params) assert audiences["object"] == "list" @@ -145,7 +145,7 @@ def test_audiences_list_with_before_param(self) -> None: params: resend.Audiences.ListParams = { "limit": 5, - "before": "later-audience-id" + "before": "later-audience-id", } audiences: resend.Audiences.ListResponse = resend.Audiences.list(params=params) assert audiences["object"] == "list" diff --git a/tests/broadcasts_test.py b/tests/broadcasts_test.py index e5f63d0..31239bc 100644 --- a/tests/broadcasts_test.py +++ b/tests/broadcasts_test.py @@ -87,6 +87,7 @@ def test_broadcasts_list(self) -> None: self.set_mock_json( { "object": "list", + "has_more": False, "data": [ { "id": "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794", @@ -110,6 +111,7 @@ def test_broadcasts_list(self) -> None: broadcasts: resend.Broadcasts.ListResponse = resend.Broadcasts.list() assert broadcasts["object"] == "list" + assert broadcasts["has_more"] is False assert len(broadcasts["data"]) == 2 broadcast = broadcasts["data"][0] @@ -127,3 +129,72 @@ def test_broadcasts_list(self) -> None: assert broadcast["created_at"] == "2024-12-01T19:32:22.980Z" assert broadcast["scheduled_at"] == "2024-12-02T19:32:22.980Z" assert broadcast["sent_at"] == "2024-12-02T19:32:22.980Z" + + def test_broadcasts_list_with_pagination_params(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": True, + "data": [ + { + "id": "broadcast-1", + "audience_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf", + "status": "draft", + "created_at": "2024-11-01T15:13:31.723Z", + "scheduled_at": None, + "sent_at": None, + }, + { + "id": "broadcast-2", + "audience_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf", + "status": "sent", + "created_at": "2024-12-01T19:32:22.980Z", + "scheduled_at": "2024-12-02T19:32:22.980Z", + "sent_at": "2024-12-02T19:32:22.980Z", + }, + ], + } + ) + + params: resend.Broadcasts.ListParams = { + "limit": 10, + "after": "previous-broadcast-id", + } + broadcasts: resend.Broadcasts.ListResponse = resend.Broadcasts.list( + params=params + ) + assert broadcasts["object"] == "list" + assert broadcasts["has_more"] is True + assert len(broadcasts["data"]) == 2 + assert broadcasts["data"][0]["id"] == "broadcast-1" + assert broadcasts["data"][1]["id"] == "broadcast-2" + + def test_broadcasts_list_with_before_param(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": False, + "data": [ + { + "id": "broadcast-3", + "audience_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf", + "status": "draft", + "created_at": "2024-10-01T15:13:31.723Z", + "scheduled_at": None, + "sent_at": None, + } + ], + } + ) + + params: resend.Broadcasts.ListParams = { + "limit": 5, + "before": "later-broadcast-id", + } + broadcasts: resend.Broadcasts.ListResponse = resend.Broadcasts.list( + params=params + ) + assert broadcasts["object"] == "list" + assert broadcasts["has_more"] is False + assert len(broadcasts["data"]) == 1 + assert broadcasts["data"][0]["id"] == "broadcast-3" diff --git a/tests/pagination_helper_test.py b/tests/pagination_helper_test.py index 0713711..3954edc 100644 --- a/tests/pagination_helper_test.py +++ b/tests/pagination_helper_test.py @@ -79,4 +79,4 @@ def test_build_paginated_path_with_integer_values(self) -> None: params = {"limit": 100, "offset": 0} result = PaginationHelper.build_paginated_path(path, params) assert "limit=100" in result - assert "offset=0" in result \ No newline at end of file + assert "offset=0" in result From 83b6ae46eca4072a1acee659f186264c6ee48225 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 17:20:53 -0300 Subject: [PATCH 4/8] feat: contacts list method pagination support --- examples/contacts.py | 16 ++++++++ resend/contacts/_contacts.py | 40 +++++++++++++++++--- tests/contacts_test.py | 72 ++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/examples/contacts.py b/examples/contacts.py index 507b7a1..d0b8afd 100644 --- a/examples/contacts.py +++ b/examples/contacts.py @@ -46,9 +46,25 @@ contacts: resend.Contacts.ListResponse = resend.Contacts.list(audience_id=audience_id) print("List of contacts") +print(f"Found {len(contacts['data'])} contacts") +print(f"Has more contacts: {contacts['has_more']}") for c in contacts["data"]: print(c) +print("\n--- Using pagination parameters ---") +if contacts["data"]: + paginated_params: resend.Contacts.ListParams = { + "limit": 2, + "after": contacts["data"][0]["id"] + } + paginated_contacts: resend.Contacts.ListResponse = resend.Contacts.list( + audience_id=audience_id, params=paginated_params + ) + print(f"Retrieved {len(paginated_contacts['data'])} contacts with pagination") + print(f"Has more contacts: {paginated_contacts['has_more']}") +else: + print("No contacts available for pagination example") + # remove by email rmed: resend.Contacts.RemoveContactResponse = resend.Contacts.remove( audience_id=audience_id, email=cont_by_email["email"] diff --git a/resend/contacts/_contacts.py b/resend/contacts/_contacts.py index 336a75a..0aa1d34 100644 --- a/resend/contacts/_contacts.py +++ b/resend/contacts/_contacts.py @@ -3,6 +3,7 @@ from typing_extensions import NotRequired, TypedDict from resend import request +from resend.pagination_helper import PaginationHelper from ._contact import Contact @@ -32,23 +33,46 @@ class RemoveContactResponse(TypedDict): Whether the contact was deleted. """ + class ListParams(TypedDict): + limit: NotRequired[int] + """ + Number of contacts to retrieve. Maximum is 100, and minimum is 1. + """ + after: NotRequired[str] + """ + The ID after which we'll retrieve more contacts (for pagination). + This ID will not be included in the returned list. + Cannot be used with the before parameter. + """ + before: NotRequired[str] + """ + The ID before which we'll retrieve more contacts (for pagination). + This ID will not be included in the returned list. + Cannot be used with the after parameter. + """ + class ListResponse(TypedDict): """ - ListResponse type that wraps a list of contact objects + ListResponse type that wraps a list of contact objects with pagination metadata Attributes: - object (str): The object type: list + object (str): The object type, always "list" data (List[Contact]): A list of contact objects + has_more (bool): Whether there are more results available """ object: str """ - The object type: list + The object type, always "list" """ data: List[Contact] """ A list of contact objects """ + has_more: bool + """ + Whether there are more results available for pagination + """ class CreateContactResponse(TypedDict): """ @@ -177,18 +201,24 @@ def update(cls, params: UpdateParams) -> UpdateContactResponse: return resp @classmethod - def list(cls, audience_id: str) -> ListResponse: + def list(cls, audience_id: str, params: Optional[ListParams] = None) -> ListResponse: """ List all contacts for the provided audience. see more: https://resend.com/docs/api-reference/contacts/list-contacts Args: audience_id (str): The audience ID + params (Optional[ListParams]): Optional pagination parameters + - limit: Number of contacts to retrieve (max 100, min 1) + - after: ID after which to retrieve more contacts + - before: ID before which to retrieve more contacts Returns: ListResponse: A list of contact objects """ - path = f"/audiences/{audience_id}/contacts" + base_path = f"/audiences/{audience_id}/contacts" + query_params = cast(Dict[Any, Any], params) if params else None + path = PaginationHelper.build_paginated_path(base_path, query_params) resp = request.Request[Contacts.ListResponse]( path=path, params={}, verb="get" ).perform_with_content() diff --git a/tests/contacts_test.py b/tests/contacts_test.py index b6a6286..4ac8974 100644 --- a/tests/contacts_test.py +++ b/tests/contacts_test.py @@ -204,6 +204,7 @@ def test_contacts_list(self) -> None: self.set_mock_json( { "object": "list", + "has_more": False, "data": [ { "id": "e169aa45-1ecf-4183-9955-b1499d5701d3", @@ -220,6 +221,8 @@ def test_contacts_list(self) -> None: contacts: resend.Contacts.ListResponse = resend.Contacts.list( audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8" ) + 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" assert contacts["data"][0].get("first_name") == "Steve" @@ -231,3 +234,72 @@ def test_should_list_contacts_raise_exception_when_no_content(self) -> None: self.set_mock_json(None) with self.assertRaises(NoContentError): _ = resend.Contacts.list(audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8") + + def test_contacts_list_with_pagination_params(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, + }, + { + "id": "contact-2", + "email": "contact2@example.com", + "first_name": "Contact", + "last_name": "Two", + "created_at": "2023-10-07T23:47:56.678Z", + "unsubscribed": False, + } + ], + } + ) + + params: resend.Contacts.ListParams = { + "limit": 10, + "after": "previous-contact-id" + } + contacts: resend.Contacts.ListResponse = resend.Contacts.list( + audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8", params=params + ) + assert contacts["object"] == "list" + assert contacts["has_more"] is True + assert len(contacts["data"]) == 2 + assert contacts["data"][0]["id"] == "contact-1" + assert contacts["data"][1]["id"] == "contact-2" + + def test_contacts_list_with_before_param(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": False, + "data": [ + { + "id": "contact-3", + "email": "contact3@example.com", + "first_name": "Contact", + "last_name": "Three", + "created_at": "2023-10-05T23:47:56.678Z", + "unsubscribed": False, + } + ], + } + ) + + params: resend.Contacts.ListParams = { + "limit": 5, + "before": "later-contact-id" + } + contacts: resend.Contacts.ListResponse = resend.Contacts.list( + audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8", params=params + ) + assert contacts["object"] == "list" + assert contacts["has_more"] is False + assert len(contacts["data"]) == 1 + assert contacts["data"][0]["id"] == "contact-3" From 06169baecb42b3497aad1ad86524dea7cb9a81f7 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 17:30:03 -0300 Subject: [PATCH 5/8] feat: domains list method pagination support --- examples/domains.py | 16 ++++++++- resend/domains/_domains.py | 45 +++++++++++++++++++++++--- tests/domains_test.py | 66 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/examples/domains.py b/examples/domains.py index 35222fa..a120391 100644 --- a/examples/domains.py +++ b/examples/domains.py @@ -33,11 +33,25 @@ print(f"Updated domain: {updated_domain['id']}") domains: resend.Domains.ListResponse = resend.Domains.list() -if not domains: +print(f"Found {len(domains['data'])} domains") +print(f"Has more domains: {domains['has_more']}") +if not domains["data"]: print("No domains found") for domain in domains["data"]: print(domain) +print("\n--- Using pagination parameters ---") +if domains["data"]: + paginated_params: resend.Domains.ListParams = { + "limit": 2, + "after": domains["data"][0]["id"] + } + paginated_domains: resend.Domains.ListResponse = resend.Domains.list(params=paginated_params) + print(f"Retrieved {len(paginated_domains['data'])} domains with pagination") + print(f"Has more domains: {paginated_domains['has_more']}") +else: + print("No domains available for pagination example") + verified_domain: resend.Domain = resend.Domains.verify(domain_id=domain["id"]) print(f"Verified") print(verified_domain) diff --git a/resend/domains/_domains.py b/resend/domains/_domains.py index b388da3..3fd59a2 100644 --- a/resend/domains/_domains.py +++ b/resend/domains/_domains.py @@ -1,28 +1,57 @@ -from typing import Any, Dict, List, Union, cast +from typing import Any, Dict, List, Optional, Union, cast from typing_extensions import Literal, NotRequired, TypedDict from resend import request from resend.domains._domain import Domain from resend.domains._record import Record +from resend.pagination_helper import PaginationHelper TlsOptions = Literal["enforced", "opportunistic"] class Domains: + class ListParams(TypedDict): + limit: NotRequired[int] + """ + Number of domains to retrieve. Maximum is 100, and minimum is 1. + """ + after: NotRequired[str] + """ + The ID after which we'll retrieve more domains (for pagination). + This ID will not be included in the returned list. + Cannot be used with the before parameter. + """ + before: NotRequired[str] + """ + The ID before which we'll retrieve more domains (for pagination). + This ID will not be included in the returned list. + Cannot be used with the after parameter. + """ + class ListResponse(TypedDict): """ - ListResponse type that wraps a list of domain objects + ListResponse type that wraps a list of domain objects with pagination metadata Attributes: + object (str): The object type, always "list" data (List[Domain]): A list of domain objects + has_more (bool): Whether there are more results available """ + object: str + """ + The object type, always "list" + """ data: List[Domain] """ A list of domain objects """ + has_more: bool + """ + Whether there are more results available for pagination + """ class CreateDomainResponse(TypedDict): """ @@ -159,15 +188,23 @@ def get(cls, domain_id: str) -> Domain: return resp @classmethod - def list(cls) -> ListResponse: + def list(cls, params: Optional[ListParams] = None) -> ListResponse: """ Retrieve a list of domains for the authenticated user. see more: https://resend.com/docs/api-reference/domains/list-domains + Args: + params (Optional[ListParams]): Optional pagination parameters + - limit: Number of domains to retrieve (max 100, min 1) + - after: ID after which to retrieve more domains + - before: ID before which to retrieve more domains + Returns: ListResponse: A list of domain objects """ - path = "/domains" + base_path = "/domains" + query_params = cast(Dict[Any, Any], params) if params else None + path = PaginationHelper.build_paginated_path(base_path, query_params) resp = request.Request[Domains.ListResponse]( path=path, params={}, verb="get" ).perform_with_content() diff --git a/tests/domains_test.py b/tests/domains_test.py index bb6a3de..1163ce1 100644 --- a/tests/domains_test.py +++ b/tests/domains_test.py @@ -113,6 +113,8 @@ def test_should_get_domains_raise_exception_when_no_content(self) -> None: def test_domains_list(self) -> None: self.set_mock_json( { + "object": "list", + "has_more": False, "data": [ { "id": "d91cd9bd-1176-453e-8fc1-35364d380206", @@ -126,6 +128,8 @@ def test_domains_list(self) -> None: ) domains = resend.Domains.list() + assert domains["object"] == "list" + assert domains["has_more"] is False assert domains["data"][0]["id"] == "d91cd9bd-1176-453e-8fc1-35364d380206" assert domains["data"][0]["name"] == "example.com" assert domains["data"][0]["status"] == "not_started" @@ -202,3 +206,65 @@ def test_should_update_domains_raise_exception_when_no_content(self) -> None: } with self.assertRaises(NoContentError): _ = resend.Domains.update(params) + + def test_domains_list_with_pagination_params(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": True, + "data": [ + { + "id": "domain-1", + "name": "example1.com", + "status": "verified", + "created_at": "2023-04-26T20:21:26.347412+00:00", + "region": "us-east-1", + }, + { + "id": "domain-2", + "name": "example2.com", + "status": "not_started", + "created_at": "2023-04-27T20:21:26.347412+00:00", + "region": "us-west-2", + } + ] + } + ) + + params: resend.Domains.ListParams = { + "limit": 10, + "after": "previous-domain-id" + } + domains: resend.Domains.ListResponse = resend.Domains.list(params=params) + assert domains["object"] == "list" + assert domains["has_more"] is True + assert len(domains["data"]) == 2 + assert domains["data"][0]["id"] == "domain-1" + assert domains["data"][1]["id"] == "domain-2" + + def test_domains_list_with_before_param(self) -> None: + self.set_mock_json( + { + "object": "list", + "has_more": False, + "data": [ + { + "id": "domain-3", + "name": "example3.com", + "status": "verified", + "created_at": "2023-04-25T20:21:26.347412+00:00", + "region": "eu-west-1", + } + ] + } + ) + + params: resend.Domains.ListParams = { + "limit": 5, + "before": "later-domain-id" + } + domains: resend.Domains.ListResponse = resend.Domains.list(params=params) + assert domains["object"] == "list" + assert domains["has_more"] is False + assert len(domains["data"]) == 1 + assert domains["data"][0]["id"] == "domain-3" From 0bf40e429b9508ec1f1dee306f5e741e631b8877 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Sun, 21 Sep 2025 17:30:23 -0300 Subject: [PATCH 6/8] chore: lint --- examples/contacts.py | 2 +- examples/domains.py | 6 ++++-- resend/contacts/_contacts.py | 4 +++- tests/contacts_test.py | 9 +++------ tests/domains_test.py | 18 ++++++------------ 5 files changed, 17 insertions(+), 22 deletions(-) diff --git a/examples/contacts.py b/examples/contacts.py index d0b8afd..fb5fbb1 100644 --- a/examples/contacts.py +++ b/examples/contacts.py @@ -55,7 +55,7 @@ if contacts["data"]: paginated_params: resend.Contacts.ListParams = { "limit": 2, - "after": contacts["data"][0]["id"] + "after": contacts["data"][0]["id"], } paginated_contacts: resend.Contacts.ListResponse = resend.Contacts.list( audience_id=audience_id, params=paginated_params diff --git a/examples/domains.py b/examples/domains.py index a120391..1f530b0 100644 --- a/examples/domains.py +++ b/examples/domains.py @@ -44,9 +44,11 @@ if domains["data"]: paginated_params: resend.Domains.ListParams = { "limit": 2, - "after": domains["data"][0]["id"] + "after": domains["data"][0]["id"], } - paginated_domains: resend.Domains.ListResponse = resend.Domains.list(params=paginated_params) + paginated_domains: resend.Domains.ListResponse = resend.Domains.list( + params=paginated_params + ) print(f"Retrieved {len(paginated_domains['data'])} domains with pagination") print(f"Has more domains: {paginated_domains['has_more']}") else: diff --git a/resend/contacts/_contacts.py b/resend/contacts/_contacts.py index 0aa1d34..c29e6fe 100644 --- a/resend/contacts/_contacts.py +++ b/resend/contacts/_contacts.py @@ -201,7 +201,9 @@ def update(cls, params: UpdateParams) -> UpdateContactResponse: return resp @classmethod - def list(cls, audience_id: str, params: Optional[ListParams] = None) -> ListResponse: + def list( + cls, audience_id: str, params: Optional[ListParams] = None + ) -> ListResponse: """ List all contacts for the provided audience. see more: https://resend.com/docs/api-reference/contacts/list-contacts diff --git a/tests/contacts_test.py b/tests/contacts_test.py index 4ac8974..c1f034b 100644 --- a/tests/contacts_test.py +++ b/tests/contacts_test.py @@ -256,14 +256,14 @@ def test_contacts_list_with_pagination_params(self) -> None: "last_name": "Two", "created_at": "2023-10-07T23:47:56.678Z", "unsubscribed": False, - } + }, ], } ) params: resend.Contacts.ListParams = { "limit": 10, - "after": "previous-contact-id" + "after": "previous-contact-id", } contacts: resend.Contacts.ListResponse = resend.Contacts.list( audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8", params=params @@ -292,10 +292,7 @@ def test_contacts_list_with_before_param(self) -> None: } ) - params: resend.Contacts.ListParams = { - "limit": 5, - "before": "later-contact-id" - } + params: resend.Contacts.ListParams = {"limit": 5, "before": "later-contact-id"} contacts: resend.Contacts.ListResponse = resend.Contacts.list( audience_id="48c269ed-9873-4d60-bdd9-cd7e6fc0b9b8", params=params ) diff --git a/tests/domains_test.py b/tests/domains_test.py index 1163ce1..c604699 100644 --- a/tests/domains_test.py +++ b/tests/domains_test.py @@ -123,7 +123,7 @@ def test_domains_list(self) -> None: "created_at": "2023-04-26T20:21:26.347412+00:00", "region": "us-east-1", } - ] + ], } ) @@ -226,15 +226,12 @@ def test_domains_list_with_pagination_params(self) -> None: "status": "not_started", "created_at": "2023-04-27T20:21:26.347412+00:00", "region": "us-west-2", - } - ] + }, + ], } ) - params: resend.Domains.ListParams = { - "limit": 10, - "after": "previous-domain-id" - } + params: resend.Domains.ListParams = {"limit": 10, "after": "previous-domain-id"} domains: resend.Domains.ListResponse = resend.Domains.list(params=params) assert domains["object"] == "list" assert domains["has_more"] is True @@ -255,14 +252,11 @@ def test_domains_list_with_before_param(self) -> None: "created_at": "2023-04-25T20:21:26.347412+00:00", "region": "eu-west-1", } - ] + ], } ) - params: resend.Domains.ListParams = { - "limit": 5, - "before": "later-domain-id" - } + params: resend.Domains.ListParams = {"limit": 5, "before": "later-domain-id"} domains: resend.Domains.ListResponse = resend.Domains.list(params=params) assert domains["object"] == "list" assert domains["has_more"] is False From cceeda28b5cc386226294103bc59212fa0e6e0fd Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Mon, 22 Sep 2025 21:16:01 -0300 Subject: [PATCH 7/8] doc: updated docstring to mention the absense of limit --- resend/audiences/_audiences.py | 2 +- resend/broadcasts/_broadcasts.py | 2 +- resend/contacts/_contacts.py | 2 +- resend/domains/_domains.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resend/audiences/_audiences.py b/resend/audiences/_audiences.py index bc3a669..2414dfc 100644 --- a/resend/audiences/_audiences.py +++ b/resend/audiences/_audiences.py @@ -130,7 +130,7 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of audiences to retrieve (max 100, min 1) + - limit: Number of audiences to retrieve (max 100, min 1). If not provided, all audiences will be returned without pagination. - after: ID after which to retrieve more audiences - before: ID before which to retrieve more audiences diff --git a/resend/broadcasts/_broadcasts.py b/resend/broadcasts/_broadcasts.py index 92170a8..4cda33b 100644 --- a/resend/broadcasts/_broadcasts.py +++ b/resend/broadcasts/_broadcasts.py @@ -290,7 +290,7 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of broadcasts to retrieve (max 100, min 1) + - limit: Number of broadcasts to retrieve (max 100, min 1). If not provided, all broadcasts will be returned without pagination. - after: ID after which to retrieve more broadcasts - before: ID before which to retrieve more broadcasts diff --git a/resend/contacts/_contacts.py b/resend/contacts/_contacts.py index c29e6fe..4d33474 100644 --- a/resend/contacts/_contacts.py +++ b/resend/contacts/_contacts.py @@ -211,7 +211,7 @@ def list( Args: audience_id (str): The audience ID params (Optional[ListParams]): Optional pagination parameters - - limit: Number of contacts to retrieve (max 100, min 1) + - 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 diff --git a/resend/domains/_domains.py b/resend/domains/_domains.py index 3fd59a2..5e7e23c 100644 --- a/resend/domains/_domains.py +++ b/resend/domains/_domains.py @@ -195,7 +195,7 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of domains to retrieve (max 100, min 1) + - limit: Number of domains to retrieve (max 100, min 1). If not provided, all domains will be returned without pagination. - after: ID after which to retrieve more domains - before: ID before which to retrieve more domains From a507b68f02b44e403b74b1edc9b0e6f9124fd693 Mon Sep 17 00:00:00 2001 From: Derich Pacheco Date: Tue, 23 Sep 2025 00:29:26 -0300 Subject: [PATCH 8/8] fix: lint --- resend/audiences/_audiences.py | 3 ++- resend/broadcasts/_broadcasts.py | 3 ++- resend/contacts/_contacts.py | 3 ++- resend/domains/_domains.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resend/audiences/_audiences.py b/resend/audiences/_audiences.py index 2414dfc..fa4925e 100644 --- a/resend/audiences/_audiences.py +++ b/resend/audiences/_audiences.py @@ -130,7 +130,8 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of audiences to retrieve (max 100, min 1). If not provided, all audiences will be returned without pagination. + - limit: Number of audiences to retrieve (max 100, min 1). + If not provided, all audiences will be returned without pagination. - after: ID after which to retrieve more audiences - before: ID before which to retrieve more audiences diff --git a/resend/broadcasts/_broadcasts.py b/resend/broadcasts/_broadcasts.py index 4cda33b..3102d66 100644 --- a/resend/broadcasts/_broadcasts.py +++ b/resend/broadcasts/_broadcasts.py @@ -290,7 +290,8 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of broadcasts to retrieve (max 100, min 1). If not provided, all broadcasts will be returned without pagination. + - limit: Number of broadcasts to retrieve (max 100, min 1). + If not provided, all broadcasts will be returned without pagination. - after: ID after which to retrieve more broadcasts - before: ID before which to retrieve more broadcasts diff --git a/resend/contacts/_contacts.py b/resend/contacts/_contacts.py index 4d33474..47ca2c0 100644 --- a/resend/contacts/_contacts.py +++ b/resend/contacts/_contacts.py @@ -211,7 +211,8 @@ def list( Args: audience_id (str): The audience ID 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. + - 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 diff --git a/resend/domains/_domains.py b/resend/domains/_domains.py index 5e7e23c..39cb85f 100644 --- a/resend/domains/_domains.py +++ b/resend/domains/_domains.py @@ -195,7 +195,8 @@ def list(cls, params: Optional[ListParams] = None) -> ListResponse: Args: params (Optional[ListParams]): Optional pagination parameters - - limit: Number of domains to retrieve (max 100, min 1). If not provided, all domains will be returned without pagination. + - limit: Number of domains to retrieve (max 100, min 1). + If not provided, all domains will be returned without pagination. - after: ID after which to retrieve more domains - before: ID before which to retrieve more domains