From fa2baed43c3f7cfde5257348573c5655e96d48fd Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Fri, 14 Aug 2026 11:53:18 -0300 Subject: [PATCH] feat(automations): duplicate endpoint Co-Authored-By: Claude Fable 5 --- resend/automations/_automations.py | 56 ++++++++++++++++++++++++++++++ tests/automations_async_test.py | 21 +++++++++++ tests/automations_test.py | 12 +++++++ 3 files changed, 89 insertions(+) diff --git a/resend/automations/_automations.py b/resend/automations/_automations.py index 6e8e85d..64bec52 100644 --- a/resend/automations/_automations.py +++ b/resend/automations/_automations.py @@ -169,6 +169,24 @@ class DeleteResponse(BaseResponse): Whether the automation was successfully deleted. """ + class DuplicateResponse(BaseResponse): + """ + DuplicateResponse is the class that wraps the response of the duplicate method. + + Attributes: + object (str): The object type, always "automation" + id (str): The ID of the newly created automation + """ + + object: str + """ + The object type, always "automation". + """ + id: str + """ + The ID of the newly created automation. + """ + class StopResponse(BaseResponse): """ StopResponse is the class that wraps the response of the stop method. @@ -443,6 +461,24 @@ def remove(cls, automation_id: str) -> "Automations.DeleteResponse": ).perform_with_content() return resp + @classmethod + def duplicate(cls, automation_id: str) -> "Automations.DuplicateResponse": + """ + Duplicate an automation. + see more: https://resend.com/docs/api-reference/automations/duplicate-automation + + Args: + automation_id (str): The automation ID + + Returns: + DuplicateResponse: The duplicate response + """ + path = f"/automations/{automation_id}/duplicate" + resp = request.Request[Automations.DuplicateResponse]( + path=path, params={}, verb="post" + ).perform_with_content() + return resp + @classmethod def stop(cls, automation_id: str) -> "Automations.StopResponse": """ @@ -564,6 +600,26 @@ async def remove_async(cls, automation_id: str) -> "Automations.DeleteResponse": ).perform_with_content() return resp + @classmethod + async def duplicate_async( + cls, automation_id: str + ) -> "Automations.DuplicateResponse": + """ + Duplicate an automation (async). + see more: https://resend.com/docs/api-reference/automations/duplicate-automation + + Args: + automation_id (str): The automation ID + + Returns: + DuplicateResponse: The duplicate response + """ + path = f"/automations/{automation_id}/duplicate" + resp = await AsyncRequest[Automations.DuplicateResponse]( + path=path, params={}, verb="post" + ).perform_with_content() + return resp + @classmethod async def stop_async(cls, automation_id: str) -> "Automations.StopResponse": """ diff --git a/tests/automations_async_test.py b/tests/automations_async_test.py index 6dbe0bc..446295c 100644 --- a/tests/automations_async_test.py +++ b/tests/automations_async_test.py @@ -123,6 +123,27 @@ async def test_automations_remove_async_raises_when_no_content(self) -> None: "b6d24b8e-af0b-4c3c-be0c-359bbd97381e" ) + async def test_automations_duplicate_async(self) -> None: + self.set_mock_json( + { + "object": "automation", + "id": "e169aa45-1ecf-4183-9955-b1499d5701d3", + } + ) + + resp = await resend.Automations.duplicate_async( + "b6d24b8e-af0b-4c3c-be0c-359bbd97381e" + ) + assert resp["object"] == "automation" + assert resp["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3" + + async def test_automations_duplicate_async_raises_when_no_content(self) -> None: + self.set_mock_json(None) + with pytest.raises(NoContentError): + _ = await resend.Automations.duplicate_async( + "b6d24b8e-af0b-4c3c-be0c-359bbd97381e" + ) + async def test_automations_stop_async(self) -> None: self.set_mock_json( { diff --git a/tests/automations_test.py b/tests/automations_test.py index 020f1c6..7a2aee5 100644 --- a/tests/automations_test.py +++ b/tests/automations_test.py @@ -135,6 +135,18 @@ def test_automations_remove(self) -> None: assert resp["id"] == "b6d24b8e-af0b-4c3c-be0c-359bbd97381e" assert resp["deleted"] is True + def test_automations_duplicate(self) -> None: + self.set_mock_json( + { + "object": "automation", + "id": "e169aa45-1ecf-4183-9955-b1499d5701d3", + } + ) + + resp = resend.Automations.duplicate("b6d24b8e-af0b-4c3c-be0c-359bbd97381e") + assert resp["object"] == "automation" + assert resp["id"] == "e169aa45-1ecf-4183-9955-b1499d5701d3" + def test_automations_stop(self) -> None: self.set_mock_json( {