Official Python SDK for Xperium CRM API
Project description
Xperium Python SDK
Official Python SDK for the Xperium CRM API. This library provides a simple and intuitive interface for integrating your Python applications with Xperium CRM.
Features
- 🚀 Easy to use: Simple, intuitive API
- 🔄 Automatic retries: Built-in retry logic with exponential backoff
- 🛡️ Type hints: Full type hint support for better IDE integration
- 📝 Comprehensive documentation: Detailed docstrings and examples
- ✅ Well tested: 100% test coverage with unit and integration tests
- 🔌 Flexible: Support for contact identification, deal management, and activity tracking
Installation
pip install xperium
Or install from source:
git clone https://github.com/xperium/xperium-python-sdk.git
cd xperium-python-sdk
pip install -e .
Quick Start
from xperium import CRMClient
from decimal import Decimal
# Initialize the client
client = CRMClient(
api_token="your-api-token"
)
# Identify or create a contact
contact, created = client.contacts.identify(
external_id="user_123",
email="user@example.com",
first_name="John",
last_name="Doe"
)
# Create a deal
deal = client.deals.create(
name="Premium Subscription",
amount=Decimal("999.99"),
contact_external_id="user_123",
currency="USD",
priority="HIGH"
)
# Log an activity
activity = client.activities.log(
title="User completed onboarding",
activity_type="USER_ACTION",
user_id="user_123",
metadata={"steps": 5, "time_spent": 120}
)
# Don't forget to close the client
client.close()
Using as Context Manager
from xperium import CRMClient
with CRMClient(api_token="your-token") as client:
contact, _ = client.contacts.identify(
external_id="user_123",
email="user@example.com"
)
# Client is automatically closed when exiting the context
Core Concepts
Authentication
The SDK uses API token authentication. You can generate an API token from your Xperium dashboard.
from xperium import CRMClient
client = CRMClient(
api_token="your-api-token",
timeout=30, # Request timeout in seconds
max_retries=3, # Maximum retry attempts
retry_delay=1.0, # Initial retry delay in seconds
)
Error Handling
The SDK provides specific exception classes for different error types:
from xperium import CRMClient
from xperium.exceptions import (
AuthenticationError,
ResourceNotFoundError,
ValidationError,
RateLimitError,
ServerError,
NetworkError,
)
client = CRMClient(api_token="your-token")
try:
contact = client.contacts.get("contact-id")
except AuthenticationError:
print("Invalid API token")
except ResourceNotFoundError:
print("Contact not found")
except ValidationError as e:
print(f"Validation failed: {e.errors}")
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after}")
except ServerError:
print("Server error occurred")
except NetworkError:
print("Network error occurred")
API Reference
Contacts
identify(external_id, email, first_name, last_name, **kwargs)
Identify or create a contact. This is the primary method for SDK user identification.
contact, created = client.contacts.identify(
external_id="user_123",
email="user@example.com",
first_name="John",
last_name="Doe",
phone="+1234567890",
title="Software Engineer"
)
lookup(external_id, email)
Lookup a contact without creating if not found.
contact = client.contacts.lookup(external_id="user_123")
if contact:
print(f"Found: {contact.full_name}")
else:
print("Contact not found")
create(email, first_name, last_name, **kwargs)
Create a new contact.
contact = client.contacts.create(
email="user@example.com",
first_name="John",
last_name="Doe"
)
get(contact_id)
Get a contact by ID.
contact = client.contacts.get("contact-uuid")
update(contact_id, **kwargs)
Update a contact.
contact = client.contacts.update(
"contact-uuid",
first_name="Jane",
title="Senior Engineer"
)
list(**filters)
List contacts with optional filters.
contacts = client.contacts.list(status="CUSTOMER")
mark_contacted(contact_id)
Mark contact as contacted.
contact = client.contacts.mark_contacted("contact-uuid")
update_status(contact_id, status)
Update contact status.
contact = client.contacts.update_status("contact-uuid", "CUSTOMER")
Deals
create(name, amount, contact_id, **kwargs)
Create a deal with flexible contact identification.
from decimal import Decimal
deal = client.deals.create(
name="Premium Subscription",
amount=Decimal("999.99"),
contact_external_id="user_123", # Or use contact_id or contact_email
currency="USD",
pipeline="Sales Pipeline", # Optional: pipeline name or ID
stage="Prospecting", # Optional: stage name or ID
priority="HIGH",
tags=["premium", "annual"],
custom_fields={"source": "website"}
)
get(deal_id)
Get a deal by ID.
deal = client.deals.get("deal-uuid")
update(deal_id, **kwargs)
Update a deal.
deal = client.deals.update(
"deal-uuid",
amount=Decimal("1499.99"),
priority="URGENT"
)
list(**filters)
List deals with optional filters.
deals = client.deals.list(status="OPEN", priority="HIGH")
move_stage(deal_id, stage_id, notes)
Move deal to a new stage.
deal = client.deals.move_stage(
"deal-uuid",
"stage-uuid",
notes="Customer requested demo"
)
get_history(deal_id)
Get stage history for a deal.
history = client.deals.get_history("deal-uuid")
by_stage(pipeline_id, **filters)
Get deals grouped by stage (for kanban view).
stages = client.deals.by_stage("pipeline-uuid", status="OPEN")
Activities
log(title, activity_type, user_id, email, **kwargs)
Log an activity from your backend system.
activity = client.activities.log(
title="User completed onboarding",
activity_type="USER_ACTION",
user_id="user_123", # external_id
email="user@example.com", # Fallback if user_id not found
description="User finished all onboarding steps",
metadata={
"steps_completed": 5,
"time_spent_seconds": 120,
"completion_rate": 100
}
)
create(title, activity_type, **kwargs)
Create an activity (generic endpoint).
activity = client.activities.create(
title="Meeting scheduled",
activity_type="MEETING",
description="Initial discovery call"
)
get(activity_id)
Get an activity by ID.
activity = client.activities.get("activity-uuid")
list(**filters)
List activities with optional filters.
activities = client.activities.list(activity_type="USER_ACTION")
timeline(related_to_type, related_to_id)
Get activity timeline for a specific entity.
timeline = client.activities.timeline("contact", "contact-uuid")
recent(activity_type)
Get recent activities (last 30 days).
recent = client.activities.recent(activity_type="DEAL_CREATED")
Complete Example
Here's a complete example showing a typical integration workflow:
from xperium import CRMClient
from decimal import Decimal
# Initialize client
with CRMClient(api_token="your-api-token") as client:
# 1. User signs up in your app
contact, created = client.contacts.identify(
external_id="user_12345",
email="john.doe@example.com",
first_name="John",
last_name="Doe",
phone="+1234567890"
)
if created:
print(f"New contact created: {contact.full_name}")
else:
print(f"Existing contact found: {contact.full_name}")
# 2. Log signup activity
client.activities.log(
title="User signed up",
activity_type="USER_ACTION",
user_id="user_12345",
metadata={"source": "website", "plan": "free"}
)
# 3. User upgrades to premium
client.activities.log(
title="User upgraded to premium",
activity_type="USER_ACTION",
user_id="user_12345",
metadata={"plan": "premium", "amount": 99.99}
)
# 4. Create a deal for the upgrade
deal = client.deals.create(
name=f"Premium Upgrade - {contact.full_name}",
amount=Decimal("99.99"),
contact_external_id="user_12345",
currency="USD",
priority="MEDIUM",
tags=["upgrade", "premium"],
custom_fields={
"previous_plan": "free",
"upgrade_date": "2024-01-15"
}
)
print(f"Deal created: {deal.name} - ${deal.amount}")
# 5. Move deal through stages as user completes onboarding
# (Assuming you have the stage IDs)
deal = client.deals.move_stage(
deal.id,
"qualification-stage-uuid",
notes="User completed profile setup"
)
# 6. Get complete activity timeline for the contact
timeline = client.activities.timeline("contact", contact.id)
print(f"Total activities: {len(timeline)}")
Development
Setting up Development Environment
# Clone the repository
git clone https://github.com/xperium/xperium-python-sdk.git
cd xperium-python-sdk
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
Running Tests
# Run unit tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=xperium --cov-report=html
# Run integration tests (requires API token)
export XPERIUM_API_TOKEN="your-api-token"
export XPERIUM_BASE_URL="http://localhost:8000"
pytest tests/test_integration.py -v
Code Formatting
# Format code with black
black xperium/ tests/
# Check with flake8
flake8 xperium/ tests/
# Type checking with mypy
mypy xperium/
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support
- 📧 Email: support@xperium.com
- 📚 Documentation: https://docs.xperium.com
- 🐛 Bug Reports: https://github.com/xperium/xperium-python-sdk/issues
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
Version 1.0.0 (2025-01-01)
- Initial release
- Contact management (identify, lookup, create, update, list)
- Deal management (create, update, move through stages)
- Activity logging and tracking
- Comprehensive error handling
- Automatic retries with exponential backoff
- Full test coverage
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xperium-1.0.0.tar.gz.
File metadata
- Download URL: xperium-1.0.0.tar.gz
- Upload date:
- Size: 31.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8eeac8c9da1317cfa8e96bcfe3a50b98ff0896bba04375858910a282b29ecee3
|
|
| MD5 |
8e4f2c6c7519dd9fb119407ba0f6a0db
|
|
| BLAKE2b-256 |
eedb05110b64a2f07d2880715459a7fee9546da79626428e547ea3385977a598
|
File details
Details for the file xperium-1.0.0-py3-none-any.whl.
File metadata
- Download URL: xperium-1.0.0-py3-none-any.whl
- Upload date:
- Size: 34.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dc0e392c3dce45dba7240173ea47da9d572a6e6fa83fef7e694839fe75bc8c2
|
|
| MD5 |
6a4e43c7028652cfef3517c1c94f75fb
|
|
| BLAKE2b-256 |
94d7abcb1c4b216ea2a14b97ffe0046acfd700e77540bd5fd221d6f4370dd2d0
|