Python SDK for Phoenix Message Analysis Services - Loan/Financial AI API Client
Project description
Apala API - Python SDK
🚀 Quick Start
Installation
# Install from source (package not yet published to PyPI)
git clone <repository-url>
cd apala_api
# Basic installation
uv sync
# Or install with development tools
uv sync --group dev
# Or install with notebook support
uv sync --group notebook
Basic Usage
from apala_client import ApalaClient, Message
# Initialize client
client = ApalaClient(
api_key="your-api-key",
base_url="https://your-server.com"
)
# Authenticate (automatic JWT token management)
client.authenticate()
# Create customer message history
messages = [
Message(content="Hi, I need help with my loan application.", channel="EMAIL", reply_or_not=False),
Message(content="What are the current interest rates?", channel="SMS", reply_or_not=True),
Message(content="When will I hear back about approval?", channel="EMAIL", reply_or_not=True)
]
# Create your candidate response
candidate = Message(
content="Thank you for your inquiry! Our current rates start at 3.5% APR for qualified borrowers. We'll review your application and respond within 2 business days.",
channel="EMAIL",
reply_or_not=True
)
# Optimize message through the AI system
optimization = client.optimize_message(
message_history=messages,
candidate_message=candidate,
customer_id="550e8400-e29b-41d4-a716-446655440000",
company_guid="550e8400-e29b-41d4-a716-446655440001"
)
print(f"Original: {optimization.original_message}")
print(f"Optimized: {optimization.optimized_message}")
print(f"Message ID: {optimization.message_id}")
# Submit feedback after customer interaction
from datetime import datetime, timezone
from apala_client import PositiveReward
send_time = datetime.now(timezone.utc)
# ... customer responds ...
reply_time = datetime.now(timezone.utc)
feedback_result = client.submit_single_feedback(
message_id=optimization.message_id,
customer_responded=True,
score="good", # "good", "bad", or "neutral"
actual_sent_message=optimization.optimized_message,
positive_rewards=[PositiveReward.LINKING_CHIRP, PositiveReward.UPDATING_ACCOUNT_NUMBER],
send_timestamp=send_time,
reply_timestamp=reply_time
)
print(f"Feedback ID: {feedback_result.id}")
print(f"Submitted at: {feedback_result.inserted_at}")
🎯 Core Features
✅ Type-Safe API
- Full TypedDict responses with IDE autocomplete
- mypy integration catches errors at development time
- No runtime surprises - all response fields are typed
✅ Complete Functionality
- Message Optimization: Enhance messages for maximum engagement (primary endpoint)
- Message Processing: Analyze customer conversations and candidate responses
- Feedback Tracking: Monitor message performance with single or bulk submission
- Authentication: Automatic JWT token management with refresh
✅ Production Ready
- Multi-Python Support: Python 3.9, 3.10, 3.11, 3.12
- Comprehensive Testing: Unit tests, integration tests, type checking
- Error Handling: Uses standard
requestsexceptions (no custom exceptions) - Validation: Client-side validation of UUIDs, zip codes, channels
✅ Developer Experience
- Interactive Demo: Marimo notebook with complete workflow
- Documentation: Full Sphinx docs with examples
- Code Quality: Ruff formatting, mypy type checking, tox multi-version testing
📖 Documentation
Authentication
The SDK uses a secure two-tier authentication system:
- API Key: Your long-lived company credentials
- JWT Tokens: Short-lived session tokens for API calls (auto-managed)
# Authentication is automatic - just provide your API key
client = ApalaClient(api_key="your-api-key")
auth_response = client.authenticate()
# JWT tokens are automatically refreshed when needed
# No manual token management required!
Message Processing Workflow
# 1. Create message objects with validation
customer_messages = [
Message(
content="I'm interested in a home loan",
channel="EMAIL",
reply_or_not=False
),
Message(
content="What documents do I need?",
channel="SMS",
reply_or_not=True
)
]
# 2. Define your candidate response
candidate_response = Message(
content="Great! For a home loan, you'll need: income verification, credit report, and bank statements. We offer competitive rates starting at 3.2% APR.",
channel="EMAIL",
reply_or_not=True
)
# 3. Optimize through AI system
result = client.optimize_message(
message_history=customer_messages,
candidate_message=candidate_response,
customer_id="customer-uuid-here",
company_guid="company-uuid-here"
)
# 4. Get typed response with IDE completion
message_id = result.message_id # Type: str
optimized_message = result.optimized_message # Type: str
recommended_channel = result.recommended_channel # Type: str
Message Optimization
Enhance your messages for better customer engagement:
# Optimize your message for maximum engagement
optimization = client.optimize_message(
message_history=customer_messages,
candidate_message=candidate_response,
customer_id="customer-uuid",
company_guid="company-uuid"
)
print(f"Original: {optimization.original_message}")
print(f"Optimized: {optimization.optimized_message}")
print(f"Recommended channel: {optimization.recommended_channel}")
print(f"Message ID: {optimization.message_id}")
Feedback Tracking
Monitor message performance and learn from customer interactions with full tracking of engagement metrics:
from datetime import datetime, timezone
from apala_client import PositiveReward
# Track when you send the message
send_time = datetime.now(timezone.utc)
# ... send message to customer ...
# Track customer response and actions
reply_time = datetime.now(timezone.utc)
# Submit comprehensive feedback with positive rewards and timestamps
# Note: Multiple feedback entries can be submitted for the same message_id
result = client.submit_single_feedback(
message_id="message-id-from-optimization",
customer_responded=True,
score="good", # "good", "bad", or "neutral"
actual_sent_message="The actual message you sent", # Optional
positive_rewards=[PositiveReward.LINKING_CHIRP, PositiveReward.UPDATING_ACCOUNT_NUMBER], # Optional list
send_timestamp=send_time, # Optional
reply_timestamp=reply_time # Optional
)
print(f"Feedback recorded with ID: {result.id}")
print(f"Submitted at: {result.inserted_at}")
# Available positive reward types (all typesafe via enum):
# - PositiveReward.UPDATING_ACCOUNT_NUMBER
# - PositiveReward.SENDING_PDF_BANK_STATEMENTS
# - PositiveReward.LINKING_CHIRP
# - PositiveReward.SIGNING_LOAN_AGREEMENT
# Or submit multiple feedback items at once
feedback_list = [
{
"message_id": "msg-uuid-1",
"customer_responded": True,
"score": "good",
"actual_sent_message": "Message 1 content",
"positive_rewards": [PositiveReward.SIGNING_LOAN_AGREEMENT, PositiveReward.LINKING_CHIRP],
"send_timestamp": datetime.now(timezone.utc),
"reply_timestamp": datetime.now(timezone.utc)
},
{
"message_id": "msg-uuid-2",
"customer_responded": False,
"score": "neutral"
}
]
results = client.submit_feedback_bulk(feedback_list)
print(f"Submitted {results.count} feedback items")
🔧 Configuration
Environment Variables
Set these for production deployment:
# Required
export APALA_API_KEY="your-production-api-key"
export APALA_BASE_URL="https://your-phoenix-server.com"
export APALA_COMPANY_GUID="your-company-uuid"
# Optional
export APALA_CUSTOMER_ID="default-customer-uuid" # For testing
Client Configuration
# Basic configuration
client = ApalaClient(
api_key="your-key",
base_url="https://api.yourcompany.com"
)
# Advanced usage with custom session
import requests
session = requests.Session()
session.timeout = 30 # Custom timeout
client = ApalaClient(api_key="your-key")
client._session = session
🧪 Testing & Development
Setup
# Clone and install in development mode with uv
git clone <repository-url>
cd apala_api
uv sync --group dev
Running Tests
# Run unit tests
uv run pytest tests/test_models.py tests/test_client.py -v
# Run with coverage
uv run pytest --cov=apala_client --cov-report=html
# Run integration tests (requires running server)
# In Fish shell:
env RUN_INTEGRATION_TESTS=1 APALA_API_KEY=test-key APALA_COMPANY_GUID=test-company-uuid uv run pytest tests/test_integration.py
# In Bash/Zsh:
export RUN_INTEGRATION_TESTS=1 APALA_API_KEY=test-key APALA_COMPANY_GUID=test-company-uuid
uv run pytest tests/test_integration.py
Code Quality
# Static type checking
uv run mypy .
# Linting
uv run ruff check .
# Code formatting
uv run ruff format .
Documentation
# Build HTML documentation
uv run sphinx-build -b html docs docs/_build/html
# Build with live reload (auto-refreshes on changes)
uv run sphinx-autobuild docs docs/_build/html --port 8001
# Clean build directory
uv run python -c "import shutil; shutil.rmtree('docs/_build', ignore_errors=True)"
# Check for broken links
uv run sphinx-build -b linkcheck docs docs/_build/linkcheck
Multi-Python Testing
# Test across Python versions
uv run tox
# Test specific version
uv run tox -e py311
📊 Interactive Demo
Try the complete workflow in an interactive notebook:
# Install notebook dependencies
uv sync --group notebook
# Run the interactive demo
cd notebooks
marimo run apala_demo_marimo.py
The demo covers:
- 🔐 Authentication setup
- 📝 Creating message history
- 🎯 Message optimization (with optional metadata)
- 📊 Feedback submission
- 🔄 Complete end-to-end workflow example
🛡️ Error Handling
The SDK uses standard Python exceptions - no custom error types to learn:
import requests
from apala_client import ApalaClient
client = ApalaClient(api_key="your-key")
try:
# All SDK methods may raise requests exceptions
response = client.optimize_message(...)
except requests.HTTPError as e:
# HTTP errors (4xx, 5xx responses)
print(f"HTTP {e.response.status_code}: {e}")
except requests.ConnectionError as e:
# Network connectivity issues
print(f"Connection failed: {e}")
except requests.Timeout as e:
# Request timeout
print(f"Request timed out: {e}")
except requests.RequestException as e:
# Any other requests-related error
print(f"Request error: {e}")
except ValueError as e:
# Data validation errors (invalid UUIDs, etc.)
print(f"Invalid data: {e}")
🔍 API Reference
ApalaClient
Main client class for all API interactions.
Constructor
ApalaClient(api_key: str, base_url: str = "http://localhost:4000")
Methods
| Method | Return Type | Description |
|---|---|---|
authenticate() |
AuthResponse |
Exchange API key for JWT tokens |
refresh_access_token() |
RefreshResponse |
Refresh access token |
message_process(...) |
MessageProcessingResponse |
Process customer messages |
optimize_message(...) |
MessageOptimizationResponse |
Optimize message content |
submit_single_feedback(...) |
FeedbackResponse |
Submit single feedback |
submit_feedback_bulk(...) |
BulkFeedbackResponse |
Submit multiple feedback items |
message_feedback(...) |
BulkFeedbackResponse |
Alias for submit_feedback_bulk |
close() |
None |
Close HTTP session |
Data Models
Message
Customer or candidate message with validation.
@dataclass
class Message:
content: str # Message text
channel: str # "SMS", "EMAIL", "OTHER"
message_id: Optional[str] = None # Auto-generated if None
send_timestamp: Optional[str] = None # Auto-generated if None
reply_or_not: bool = False # Whether this is a reply
Feedback Submission
Submit feedback using the client methods directly (no model class needed):
from datetime import datetime
from apala_client import PositiveReward
# Single feedback submission
# Note: Multiple feedback entries can be submitted for the same message_id
client.submit_single_feedback(
message_id: str, # ID from optimization response
customer_responded: bool, # Did customer respond?
score: str, # Quality rating: "good", "bad", or "neutral"
actual_sent_message: Optional[str] = None, # What you actually sent
positive_rewards: Optional[List[PositiveReward]] = None, # Customer actions (list)
send_timestamp: Optional[datetime] = None, # When sent
reply_timestamp: Optional[datetime] = None # When customer replied
)
# Bulk feedback submission
client.submit_feedback_bulk([
{
"message_id": str,
"customer_responded": bool,
"score": str, # "good", "bad", or "neutral"
"actual_sent_message": str, # Optional
"positive_rewards": List[PositiveReward], # Optional list
"send_timestamp": datetime, # Optional
"reply_timestamp": datetime # Optional
},
# ... more feedback items
])
Response Types
All API responses are fully typed with Pydantic models:
AuthResponse
class AuthResponse(BaseModel):
access_token: str
refresh_token: str
token_type: str
expires_in: int
company_id: str
company_name: str
MessageOptimizationResponse
class MessageOptimizationResponse(BaseModel):
message_id: str
optimized_message: str
recommended_channel: str
original_message: str
FeedbackResponse
class FeedbackResponse(BaseModel):
id: str
message_id: str
customer_responded: bool
score: Literal["good", "bad", "neutral"]
actual_sent_message: Optional[str]
positive_rewards: List[str] # Customer actions indicating engagement
send_timestamp: Optional[str] # When message was sent
reply_timestamp: Optional[str] # When customer replied
inserted_at: str
BulkFeedbackResponse
class BulkFeedbackResponse(BaseModel):
success: bool
count: int
feedback: List[FeedbackItemResponse]
See full API documentation for complete type definitions.
🤝 Contributing
We welcome contributions! Please see our contributing guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Run the test suite (
pytestandmypy apala_client) - Commit your changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Create a Pull Request
Development Setup
git clone <your-fork>
cd apala_api
uv sync --group dev
# Run all checks before submitting
uv run pytest # Unit tests
uv run mypy apala_client # Type checking
uv run ruff check apala_client # Linting
uv run ruff format apala_client # Formatting
uv run tox # Multi-Python testing
📄 License
Copyright (c) 2025 Apala Cap. All rights reserved.
This software is proprietary and confidential. Unauthorized copying, distribution, or use of this software, via any medium, is strictly prohibited.
🔗 Links
- Documentation: Full API Documentation
- Source Code: GitHub Repository
- Issue Tracker: GitHub Issues
- PyPI Package: apala-api
💬 Support
- GitHub Issues: For bugs and feature requests
- Documentation: Complete API reference and guides
- Type Safety: Full mypy support for development-time error catching
Apala API - Proprietary Software by Apala Cap
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 apala_api-2.1.0rc2.tar.gz.
File metadata
- Download URL: apala_api-2.1.0rc2.tar.gz
- Upload date:
- Size: 8.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48355d93105b98c5507a9dff5858a48c7d951ded9821f687adf70cd39280698d
|
|
| MD5 |
69d4ccf612a3c38f84e596e1d5fea51c
|
|
| BLAKE2b-256 |
73132db6482c571a83dd83a67accaf550abf83059a460c95a8e3da2cad33bb95
|
File details
Details for the file apala_api-2.1.0rc2-py3-none-any.whl.
File metadata
- Download URL: apala_api-2.1.0rc2-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c09dc7e3c2e59a9e9f828d96d14f3f62de18e5e6699adae967db26c23e35d69
|
|
| MD5 |
bf8911fd4209f848d20663ca7b5c9c9c
|
|
| BLAKE2b-256 |
97a222e4e6181412b9f621d31141f70b2052db0b3ee41dd4c546d5db9b497942
|