Skip to content
Merged
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
25 changes: 14 additions & 11 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,34 +158,34 @@ The following examples show the structure and planned functionality but are not
The contact groups resource is fully implemented with all CRUD operations:

### 🔧 Available Functions
1. **List Groups** - `client.contact_groups.list()`
1. **List Groups** - `client.services.contact_groups.list()`
- Uses GET `/api/v1/contacts-groups`
- Pagination and search support
- Field filtering capabilities

2. **Create Group** - `client.contact_groups.create()`
2. **Create Group** - `client.services.contact_groups.create()`
- Uses POST `/api/v1/contacts-groups`
- Metadata and contact assignment
- Validation and error handling

3. **Update Group** - `client.contact_groups.update()`
3. **Update Group** - `client.services.contact_groups.update()`
- Uses PUT `/api/v1/contacts-groups/{group_id}`
- Partial updates with metadata
- Flexible field modification

4. **Get Group** - `client.contact_groups.get_by_id()`
4. **Get Group** - `client.services.contact_groups.get_by_id()`
- Uses GET `/api/v1/contacts-groups/{group_id}`
- Complete group information retrieval

5. **Delete Group** - `client.contact_groups.delete_by_id()`
5. **Delete Group** - `client.services.contact_groups.delete_by_id()`
- Uses DELETE `/api/v1/contacts-groups/{group_id}`
- Individual group deletion with approval

6. **Bulk Delete** - `client.contact_groups.delete_bulk()`
6. **Bulk Delete** - `client.services.contact_groups.delete_bulk()`
- Uses DELETE `/api/v1/contacts-groups`
- Multiple group deletion with contact transfer

7. **Search Groups** - `client.contact_groups.search()`
7. **Search Groups** - `client.services.contact_groups.search()`
- Uses GET `/api/v1/contacts-groups`
- Advanced search with field filtering

Expand All @@ -201,23 +201,26 @@ The contact groups resource is fully implemented with all CRUD operations:
```python
from devo_global_comms_python.models.contact_groups import CreateContactsGroupDto

# Create new contact group
# Create new contact group (using new services namespace)
group_data = CreateContactsGroupDto(
name="VIP Customers",
description="High-value customers",
contact_ids=["contact1", "contact2"],
metadata={"priority": "high"}
)
group = client.contact_groups.create(group_data)
group = client.services.contact_groups.create(group_data)

# List with pagination
groups = client.contact_groups.list(page=1, limit=10, search="VIP")
groups = client.services.contact_groups.list(page=1, limit=10, search="VIP")

# Search groups
search_results = client.contact_groups.search(
search_results = client.services.contact_groups.search(
query="priority",
fields=["name", "description"]
)

# Backward compatibility (deprecated - shows warning)
# groups = client.contact_groups.list() # Still works but deprecated
```

## 🔧 Configuration Notes
Expand Down
14 changes: 11 additions & 3 deletions examples/basic_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,23 @@ def main():
resources.append(("💬 WhatsApp", "Placeholder", "whatsapp_example.py"))
if hasattr(client, "contacts"):
resources.append(("👥 Contacts", "Placeholder", "contacts_example.py"))
if hasattr(client, "contact_groups"):
resources.append(("🗂️ Contact Groups", "Implemented", "contact_groups_example.py"))
if hasattr(client, "services") and hasattr(client.services, "contact_groups"):
resources.append(("🗂️ Contact Groups", "Implemented (Services)", "contact_groups_example.py"))
if hasattr(client, "rcs"):
resources.append(("🎴 RCS", "Placeholder", "rcs_example.py"))
if hasattr(client, "messages"):
resources.append(("📬 Messages", "Implemented", "omni_channel_example.py"))

for resource, status, example_file in resources:
print(f" {resource:<12} - {status:<12} -> {example_file}")
print(f" {resource:<18} - {status:<20} -> {example_file}")

# Services namespace information
if hasattr(client, "services"):
print("\n🏢 Services Namespace:")
print("-" * 30)
print(" 🗂️ Contact Groups - client.services.contact_groups")
print(" 👥 Contacts (Future) - client.services.contacts")
print(" 📊 Analytics (Future) - client.services.analytics")

# Quick SMS test if available
if hasattr(client, "sms"):
Expand Down
46 changes: 21 additions & 25 deletions examples/contact_groups_example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
from datetime import datetime

Expand All @@ -11,13 +10,6 @@


def main():
"""
Demonstrate contact groups management capabilities.

Shows how to create, read, update and delete contact groups
using the Contact Groups API.
"""

# Initialize the client
api_key = os.getenv("DEVO_API_KEY")
if not api_key:
Expand All @@ -28,11 +20,13 @@ def main():

print("🗂️ Devo Global Communications - Contact Groups Management Example")
print("=" * 75)
print("📋 Using services namespace: client.services.contact_groups")
print()

# Example 1: List existing contact groups
print("\n📋 Listing existing contact groups...")
try:
groups_list = client.contact_groups.list(page=1, limit=5)
groups_list = client.services.contact_groups.list(page=1, limit=5)
print(f"✅ Found {groups_list.total} total groups")
print(f" Page: {groups_list.page}/{groups_list.total_pages}")
print(f" Showing: {len(groups_list.groups)} groups")
Expand Down Expand Up @@ -63,7 +57,7 @@ def main():
},
)

new_group = client.contact_groups.create(new_group_data)
new_group = client.services.contact_groups.create(new_group_data)
print("✅ Contact group created successfully!")
print(f" 📁 Name: {new_group.name}")
print(f" 🆔 ID: {new_group.id}")
Expand All @@ -88,7 +82,7 @@ def main():
metadata={"updated_by": "api_example", "updated_at": datetime.now().isoformat(), "version": "2.0"},
)

updated_group = client.contact_groups.update(created_group_id, update_data)
updated_group = client.services.contact_groups.update(created_group_id, update_data)
print("✅ Contact group updated successfully!")
print(f" 📁 New name: {updated_group.name}")
print(f" 📝 New description: {updated_group.description}")
Expand All @@ -102,7 +96,7 @@ def main():
if created_group_id:
print(f"\n🔍 Retrieving specific group {created_group_id}...")
try:
specific_group = client.contact_groups.get_by_id(created_group_id)
specific_group = client.services.contact_groups.get_by_id(created_group_id)
print("✅ Group retrieved successfully!")
print(f" 📁 Name: {specific_group.name}")
print(f" 📝 Description: {specific_group.description}")
Expand All @@ -115,7 +109,9 @@ def main():
# Example 5: Search contact groups
print("\n🔎 Searching contact groups...")
try:
search_results = client.contact_groups.search(query="demo", fields=["name", "description"], page=1, limit=10)
search_results = client.services.contact_groups.search(
query="demo", fields=["name", "description"], page=1, limit=10
)
print(f"✅ Search completed! Found {search_results.total} matching groups")

for i, group in enumerate(search_results.groups, 1):
Expand All @@ -130,7 +126,7 @@ def main():
# Example 6: Advanced listing with filters
print("\n🔧 Advanced group listing with filters...")
try:
filtered_groups = client.contact_groups.list(
filtered_groups = client.services.contact_groups.list(
page=1, limit=3, search="demo", search_fields=["name", "description"]
)
print("✅ Filtered listing completed!")
Expand All @@ -157,7 +153,7 @@ def main():
metadata={"bulk_demo": True, "group_number": i + 1},
)

bulk_group = client.contact_groups.create(bulk_group_data)
bulk_group = client.services.contact_groups.create(bulk_group_data)
bulk_group_ids.append(bulk_group.id)
print(f" ✅ Created bulk group {i+1}: {bulk_group.name}")

Expand All @@ -170,7 +166,7 @@ def main():
if created_group_id:
print(f"\n🗑️ Deleting individual group {created_group_id}...")
try:
deleted_group = client.contact_groups.delete_by_id(created_group_id, approve="yes")
deleted_group = client.services.contact_groups.delete_by_id(created_group_id, approve="yes")
print("✅ Individual group deleted successfully!")
print(f" 📁 Deleted group: {deleted_group.name}")

Expand All @@ -185,17 +181,17 @@ def main():
backup_group_data = CreateContactsGroupDto(
name="Backup Group for Bulk Delete Demo", description="Temporary group to receive transferred contacts"
)
backup_group = client.contact_groups.create(backup_group_data)
backup_group = client.services.contact_groups.create(backup_group_data)

# Perform bulk deletion
bulk_delete_data = DeleteContactsGroupsDto(group_ids=bulk_group_ids, transfer_contacts_to=backup_group.id)

bulk_delete_result = client.contact_groups.delete_bulk(bulk_delete_data, approve="yes")
bulk_delete_result = client.services.contact_groups.delete_bulk(bulk_delete_data, approve="yes")
print("✅ Bulk deletion completed successfully!")
print(f" 📊 Operation result: {bulk_delete_result.name}")

# Clean up backup group
client.contact_groups.delete_by_id(backup_group.id, approve="yes")
client.services.contact_groups.delete_by_id(backup_group.id, approve="yes")
print(" 🧹 Cleaned up backup group")

except Exception as e:
Expand All @@ -205,7 +201,7 @@ def main():
print("\n⚠️ Error handling demonstration...")
try:
# Try to get a non-existent group
client.contact_groups.get_by_id("non_existent_group_id")
client.services.contact_groups.get_by_id("non_existent_group_id")

except Exception as e:
print(f"✅ Properly handled expected error: {type(e).__name__}")
Expand Down Expand Up @@ -277,7 +273,7 @@ def contact_group_management_workflow():
name=group_type["name"], description=group_type["description"], metadata=group_type["metadata"]
)

group = client.contact_groups.create(group_data)
group = client.services.contact_groups.create(group_data)
created_groups.append(group)
print(f" ✅ Created: {group.name}")

Expand Down Expand Up @@ -310,7 +306,7 @@ def contact_group_management_workflow():
},
)

client.contact_groups.update(vip_group.id, update_data)
client.services.contact_groups.update(vip_group.id, update_data)
print(" ✅ Updated VIP group with enhanced metadata")

except Exception as e:
Expand All @@ -326,16 +322,16 @@ def contact_group_management_workflow():
temp_group_data = CreateContactsGroupDto(
name="Temporary Archive", description="Temporary group for workflow cleanup"
)
temp_group = client.contact_groups.create(temp_group_data)
temp_group = client.services.contact_groups.create(temp_group_data)

# Bulk delete with contact transfer
delete_data = DeleteContactsGroupsDto(group_ids=group_ids, transfer_contacts_to=temp_group.id)

client.contact_groups.delete_bulk(delete_data, approve="yes")
client.services.contact_groups.delete_bulk(delete_data, approve="yes")
print(f" ✅ Bulk deleted {len(group_ids)} demonstration groups")

# Delete temporary group
client.contact_groups.delete_by_id(temp_group.id, approve="yes")
client.services.contact_groups.delete_by_id(temp_group.id, approve="yes")
print(" ✅ Cleaned up temporary archive group")

except Exception as e:
Expand Down
38 changes: 21 additions & 17 deletions src/devo_global_comms_python/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,46 @@

from .auth import APIKeyAuth
from .exceptions import DevoAPIException, DevoAuthenticationException, DevoException, DevoMissingAPIKeyException
from .resources.contact_groups import ContactGroupsResource
from .resources.contacts import ContactsResource
from .resources.email import EmailResource
from .resources.messages import MessagesResource
from .resources.rcs import RCSResource
from .resources.sms import SMSResource
from .resources.whatsapp import WhatsAppResource
from .services import ServicesNamespace


class DevoClient:
"""
Main client for interacting with the Devo Global Communications API.

This client follows a resource-based pattern,
where each communication channel (SMS, Email, etc.) is accessed as a
resource with its own methods.
This client follows a resource-based pattern with two main namespaces:
- Messaging resources: Direct access to communication channels (SMS, Email, etc.)
- Services namespace: Organized access to data management services

Example:
>>> client = DevoClient(api_key="your-api-key")
>>> # Send SMS using new API
>>>
>>> # Messaging resources (direct access)
>>> response = client.sms.send_sms(
... recipient="+1234567890",
... message="Hello, World!",
... sender="+0987654321"
... )
>>> print(f"Message ID: {response.id}")
>>> print(f"Status: {response.status}")
>>>
>>> # Get available senders
>>> senders = client.sms.get_senders()
>>> for sender in senders.senders:
... print(f"Sender: {sender.phone_number}")
>>> # Services namespace (organized access)
>>> groups = client.services.contact_groups.list()
>>> for group in groups.groups:
... print(f"Group: {group.name}")
>>>
>>> # Get available numbers
>>> numbers = client.sms.get_available_numbers(region="US", limit=5)
>>> for number_info in numbers.numbers:
... for feature in number_info.features:
... print(f"Number: {feature.phone_number}")
>>> # Omni-channel messaging
>>> from devo_global_comms_python.models.messages import SendMessageDto
>>> message = client.messages.send(SendMessageDto(
... channel="sms",
... to="+1234567890",
... payload={"text": "Hello World"}
... ))
"""

DEFAULT_BASE_URL = "https://global-api-development.devotel.io/api/v1"
Expand Down Expand Up @@ -82,15 +84,17 @@ def __init__(
# Set up session with retry strategy
self.session = session or self._create_session(max_retries)

# Initialize resources
# Initialize messaging resources
self.sms = SMSResource(self)
self.email = EmailResource(self)
self.whatsapp = WhatsAppResource(self)
self.rcs = RCSResource(self)
self.contacts = ContactsResource(self)
self.contact_groups = ContactGroupsResource(self)
self.messages = MessagesResource(self)

# Initialize services namespace
self.services = ServicesNamespace(self)

def _create_session(self, max_retries: int) -> requests.Session:
"""Create a requests session with retry strategy."""
session = requests.Session()
Expand Down
Loading
Loading