Skip to content

Commit df2d23b

Browse files
committed
merge main
2 parents 203f313 + 6dd113f commit df2d23b

6 files changed

Lines changed: 563 additions & 0 deletions

File tree

examples/topics.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import os
2+
3+
import resend
4+
5+
if not os.environ["RESEND_API_KEY"]:
6+
raise EnvironmentError("RESEND_API_KEY is missing")
7+
8+
9+
# Create a new topic
10+
create_params: resend.Topics.CreateParams = {
11+
"name": "Weekly Newsletter",
12+
"default_subscription": "opt_in",
13+
"description": "Subscribe to our weekly newsletter for updates",
14+
}
15+
16+
topic: resend.Topics.CreateTopicResponse = resend.Topics.create(create_params)
17+
print(f"Created topic with ID: {topic['id']}")
18+
print(topic)
19+
20+
# Retrieve the topic
21+
retrieved: resend.Topic = resend.Topics.get(topic["id"])
22+
print("\nRetrieved topic:")
23+
print(retrieved)
24+
25+
# Update the topic
26+
update_params: resend.Topics.UpdateParams = {
27+
"name": "Monthly Newsletter",
28+
"description": "Subscribe to our monthly newsletter for updates",
29+
}
30+
31+
updated: resend.Topics.UpdateTopicResponse = resend.Topics.update(
32+
id=topic["id"], params=update_params
33+
)
34+
print(f"\nUpdated topic with ID: {updated['id']}")
35+
print(updated)
36+
37+
# Retrieve the updated topic to see changes
38+
updated_topic: resend.Topic = resend.Topics.get(topic["id"])
39+
print("\nRetrieved updated topic:")
40+
print(updated_topic)
41+
42+
# List all topics
43+
list_response: resend.Topics.ListResponse = resend.Topics.list()
44+
print("\nList of topics:")
45+
print(f"Found {len(list_response['data'])} topics")
46+
print(f"Has more topics: {list_response['has_more']}")
47+
for t in list_response["data"]:
48+
print(f" - {t['name']} ({t['id']}): {t['default_subscription']}")
49+
50+
# List topics with pagination parameters
51+
print("\n--- Using pagination parameters ---")
52+
if list_response["data"]:
53+
paginated_params: resend.Topics.ListParams = {
54+
"limit": 5,
55+
"after": list_response["data"][0]["id"],
56+
}
57+
paginated_topics: resend.Topics.ListResponse = resend.Topics.list(
58+
params=paginated_params
59+
)
60+
print(f"Retrieved {len(paginated_topics['data'])} topics with pagination")
61+
print(f"Has more topics: {paginated_topics['has_more']}")
62+
else:
63+
print("No topics available for pagination example")
64+
65+
# Delete the topic
66+
removed: resend.Topics.RemoveTopicResponse = resend.Topics.remove(id=topic["id"])
67+
print(f"\nDeleted topic with ID: {removed['id']}")
68+
print(f"Deleted: {removed['deleted']}")
69+
print(removed)

resend/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from .http_client import HTTPClient
1919
from .http_client_requests import RequestsClient
2020
from .request import Request
21+
from .topics._topic import Topic
22+
from .topics._topics import Topics
2123
from .version import __version__, get_version
2224
from .webhooks._webhook import Webhook
2325
from .webhooks._webhooks import Webhooks
@@ -44,6 +46,7 @@
4446
"Contacts",
4547
"Broadcasts",
4648
"Webhooks",
49+
"Topics",
4750
# Types
4851
"Audience",
4952
"Contact",
@@ -55,6 +58,7 @@
5558
"Tag",
5659
"Broadcast",
5760
"Webhook",
61+
"Topic",
5862
"BatchValidationError",
5963
# Default HTTP Client
6064
"RequestsClient",

resend/topics/__init__.py

Whitespace-only changes.

resend/topics/_topic.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing_extensions import TypedDict
2+
3+
4+
class Topic(TypedDict):
5+
id: str
6+
"""
7+
The unique identifier of the topic.
8+
"""
9+
name: str
10+
"""
11+
The topic name.
12+
"""
13+
default_subscription: str
14+
"""
15+
The default subscription preference for new contacts. Possible values: opt_in or opt_out.
16+
"""
17+
description: str
18+
"""
19+
The topic description.
20+
"""
21+
created_at: str
22+
"""
23+
The date and time the topic was created.
24+
"""

resend/topics/_topics.py

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
from typing import Any, Dict, List, Optional, cast
2+
3+
from typing_extensions import NotRequired, TypedDict
4+
5+
from resend import request
6+
from resend.pagination_helper import PaginationHelper
7+
8+
from ._topic import Topic
9+
10+
11+
class Topics:
12+
13+
class CreateTopicResponse(TypedDict):
14+
"""
15+
CreateTopicResponse is the type that wraps the response of the topic that was created
16+
17+
Attributes:
18+
id (str): The ID of the created topic
19+
"""
20+
21+
id: str
22+
"""
23+
The ID of the created topic
24+
"""
25+
26+
class CreateParams(TypedDict):
27+
name: str
28+
"""
29+
The topic name. Max length is 50 characters.
30+
"""
31+
default_subscription: str
32+
"""
33+
The default subscription preference for new contacts. Possible values: opt_in or opt_out.
34+
This value cannot be changed later.
35+
"""
36+
description: NotRequired[str]
37+
"""
38+
The topic description. Max length is 200 characters.
39+
"""
40+
41+
class UpdateTopicResponse(TypedDict):
42+
"""
43+
UpdateTopicResponse is the type that wraps the response of the topic that was updated
44+
45+
Attributes:
46+
id (str): The ID of the updated topic
47+
"""
48+
49+
id: str
50+
"""
51+
The ID of the updated topic
52+
"""
53+
54+
class UpdateParams(TypedDict, total=False):
55+
name: str
56+
"""
57+
The topic name. Max length is 50 characters.
58+
"""
59+
description: str
60+
"""
61+
The topic description. Max length is 200 characters.
62+
"""
63+
64+
class RemoveTopicResponse(TypedDict):
65+
"""
66+
RemoveTopicResponse is the type that wraps the response of the topic that was removed
67+
68+
Attributes:
69+
object (str): The object type, "topic"
70+
id (str): The ID of the removed topic
71+
deleted (bool): Whether the topic was deleted
72+
"""
73+
74+
object: str
75+
"""
76+
The object type, "topic"
77+
"""
78+
id: str
79+
"""
80+
The ID of the removed topic
81+
"""
82+
deleted: bool
83+
"""
84+
Whether the topic was deleted
85+
"""
86+
87+
class ListParams(TypedDict):
88+
limit: NotRequired[int]
89+
"""
90+
Number of topics to retrieve. Maximum is 100, and minimum is 1.
91+
"""
92+
after: NotRequired[str]
93+
"""
94+
The ID after which we'll retrieve more topics (for pagination).
95+
This ID will not be included in the returned list.
96+
Cannot be used with the before parameter.
97+
"""
98+
before: NotRequired[str]
99+
"""
100+
The ID before which we'll retrieve more topics (for pagination).
101+
This ID will not be included in the returned list.
102+
Cannot be used with the after parameter.
103+
"""
104+
105+
class ListResponse(TypedDict):
106+
"""
107+
ListResponse type that wraps a list of topic objects with pagination metadata
108+
109+
Attributes:
110+
object (str): The object type, always "list"
111+
data (List[Topic]): A list of topic objects
112+
has_more (bool): Whether there are more results available
113+
"""
114+
115+
object: str
116+
"""
117+
The object type, always "list"
118+
"""
119+
data: List[Topic]
120+
"""
121+
A list of topic objects
122+
"""
123+
has_more: bool
124+
"""
125+
Whether there are more results available for pagination
126+
"""
127+
128+
@classmethod
129+
def create(cls, params: CreateParams) -> CreateTopicResponse:
130+
"""
131+
Create a topic.
132+
see more: https://resend.com/docs/api-reference/topics/create-topic
133+
134+
Args:
135+
params (CreateParams): The topic creation parameters
136+
- name: The topic name (max 50 characters)
137+
- default_subscription: The default subscription preference ("opt_in" or "opt_out")
138+
- description: Optional topic description (max 200 characters)
139+
140+
Returns:
141+
CreateTopicResponse: The created topic response with the topic ID
142+
"""
143+
144+
path = "/topics"
145+
resp = request.Request[Topics.CreateTopicResponse](
146+
path=path, params=cast(Dict[Any, Any], params), verb="post"
147+
).perform_with_content()
148+
return resp
149+
150+
@classmethod
151+
def get(cls, id: str) -> Topic:
152+
"""
153+
Retrieve a single topic by its ID.
154+
see more: https://resend.com/docs/api-reference/topics/get-topic
155+
156+
Args:
157+
id (str): The topic ID
158+
159+
Returns:
160+
Topic: The topic object
161+
"""
162+
path = f"/topics/{id}"
163+
resp = request.Request[Topic](
164+
path=path, params={}, verb="get"
165+
).perform_with_content()
166+
return resp
167+
168+
@classmethod
169+
def update(cls, id: str, params: UpdateParams) -> UpdateTopicResponse:
170+
"""
171+
Update an existing topic.
172+
see more: https://resend.com/docs/api-reference/topics/update-topic
173+
174+
Args:
175+
id (str): The topic ID
176+
params (UpdateParams): The topic update parameters
177+
- name: Optional topic name (max 50 characters)
178+
- description: Optional topic description (max 200 characters)
179+
180+
Returns:
181+
UpdateTopicResponse: The updated topic response with the topic ID
182+
"""
183+
path = f"/topics/{id}"
184+
resp = request.Request[Topics.UpdateTopicResponse](
185+
path=path, params=cast(Dict[Any, Any], params), verb="patch"
186+
).perform_with_content()
187+
return resp
188+
189+
@classmethod
190+
def remove(cls, id: str) -> RemoveTopicResponse:
191+
"""
192+
Delete a single topic.
193+
see more: https://resend.com/docs/api-reference/topics/delete-topic
194+
195+
Args:
196+
id (str): The topic ID
197+
198+
Returns:
199+
RemoveTopicResponse: The removed topic response
200+
"""
201+
path = f"/topics/{id}"
202+
resp = request.Request[Topics.RemoveTopicResponse](
203+
path=path, params={}, verb="delete"
204+
).perform_with_content()
205+
return resp
206+
207+
@classmethod
208+
def list(cls, params: Optional[ListParams] = None) -> ListResponse:
209+
"""
210+
Retrieve a list of topics.
211+
see more: https://resend.com/docs/api-reference/topics/list-topics
212+
213+
Args:
214+
params (Optional[ListParams]): Optional pagination parameters
215+
- limit: Number of topics to retrieve (max 100, min 1).
216+
If not provided, all topics will be returned without pagination.
217+
- after: ID after which to retrieve more topics
218+
- before: ID before which to retrieve more topics
219+
220+
Returns:
221+
ListResponse: A list of topic objects
222+
"""
223+
base_path = "/topics"
224+
query_params = cast(Dict[Any, Any], params) if params else None
225+
path = PaginationHelper.build_paginated_path(base_path, query_params)
226+
resp = request.Request[Topics.ListResponse](
227+
path=path, params={}, verb="get"
228+
).perform_with_content()
229+
return resp

0 commit comments

Comments
 (0)