From 2857bdf7df895b9b0530ee3bf7f766bba58f55e7 Mon Sep 17 00:00:00 2001 From: Gabriel Miranda Date: Fri, 14 Aug 2026 15:33:25 -0300 Subject: [PATCH] fix(contacts): properties response shape Co-Authored-By: Claude Fable 5 --- examples/contacts_global.py | 3 ++- resend/contacts/_contact.py | 15 +++++++++++++-- tests/contacts_test.py | 8 ++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/examples/contacts_global.py b/examples/contacts_global.py index 62b6bb1..6188e81 100644 --- a/examples/contacts_global.py +++ b/examples/contacts_global.py @@ -48,7 +48,8 @@ print("Retrieved contact by ID:") print(cont_by_id) if "properties" in cont_by_id: - print(f"Custom properties: {cont_by_id['properties']}") + for name, prop in cont_by_id["properties"].items(): + print(f"Custom property {name}: {prop['value']} ({prop['type']})") # List all global contacts print("\n--- Listing all global contacts ---") diff --git a/resend/contacts/_contact.py b/resend/contacts/_contact.py index 4089e43..41b35ba 100644 --- a/resend/contacts/_contact.py +++ b/resend/contacts/_contact.py @@ -1,8 +1,19 @@ -from typing import Any, Dict +from typing import Dict, Union from typing_extensions import NotRequired, TypedDict +class ContactPropertyValue(TypedDict): + value: Union[str, int, float, bool] + """ + The property value, a string, number, or boolean depending on type. + """ + type: str + """ + The property type ("string", "number", or "boolean"). + """ + + class Contact(TypedDict): id: str """ @@ -28,7 +39,7 @@ class Contact(TypedDict): """ The unsubscribed status of the contact. """ - properties: NotRequired[Dict[str, Any]] + properties: NotRequired[Dict[str, ContactPropertyValue]] """ Custom properties for the contact. Only available for global contacts. """ diff --git a/tests/contacts_test.py b/tests/contacts_test.py index 49841fc..103eb5b 100644 --- a/tests/contacts_test.py +++ b/tests/contacts_test.py @@ -377,14 +377,16 @@ def test_contacts_get_global(self) -> None: "last_name": "Contact", "created_at": "2023-10-06 23:47:56.678+00", "unsubscribed": False, - "properties": {"tier": "premium"}, + "properties": {"tier": {"value": "premium", "type": "string"}}, } ) contact: resend.Contact = resend.Contacts.get(id="global-contact-123") assert contact["id"] == "global-contact-123" assert contact["email"] == "global@example.com" - assert contact.get("properties") == {"tier": "premium"} + assert contact.get("properties") == { + "tier": {"value": "premium", "type": "string"} + } def test_contacts_list_global(self) -> None: self.set_mock_json( @@ -399,7 +401,6 @@ def test_contacts_list_global(self) -> None: "last_name": "One", "created_at": "2023-10-06 23:47:56.678+00", "unsubscribed": False, - "properties": {"tier": "free"}, }, { "id": "global-2", @@ -408,7 +409,6 @@ def test_contacts_list_global(self) -> None: "last_name": "Two", "created_at": "2023-10-07 23:47:56.678+00", "unsubscribed": False, - "properties": {"tier": "premium"}, }, ], }