Skip to main content

Zo Passport Python SDK - Phone to Avatar to Passport authentication for Zo World.

Project description

ZoPassport Python SDK

PyPI version Python 3.11+ License: MIT Tests

The official Python SDK for Zo World authentication and passport management. Provides seamless integration with the ZoPassport API for phone-based authentication, user profiles, avatar generation, and wallet operations.

✨ Features

  • 📱 Phone Authentication - OTP-based authentication with phone numbers
  • 🔐 Secure Session Management - Encrypted storage with automatic token refresh
  • 👤 User Profile Management - Fetch and update user profiles
  • 🎨 Avatar Generation - Generate and manage user avatars
  • 💰 Wallet Integration - Check balances and transactions on Base & Avalanche
  • 🔄 Automatic Token Refresh - Built-in token refresh with configurable intervals
  • 🛡️ Comprehensive Error Handling - Specific exception types for all failure scenarios
  • 🔁 Retry Logic - Exponential backoff for failed requests
  • 📊 Rate Limit Handling - Automatic rate limit detection and retry-after support
  • 🔒 Encrypted Storage - Optional encryption for sensitive data at rest

📦 Installation

Using pip

pip install zopassport

Using uv (recommended for development)

uv add zopassport

Development Installation

git clone https://github.com/ZoHouse/zopassport.git
cd zopassport
pip install -e ".[dev]"

🚀 Quick Start

import asyncio
from zopassport import ZoPassportSDK

async def main():
    # Initialize SDK
    sdk = ZoPassportSDK(
        client_key="YOUR_CLIENT_KEY",
        debug=True  # Enable debug logging
    )
    await sdk.initialize()

    # Check if already authenticated
    if sdk.is_authenticated:
        print(f"Welcome back, {sdk.user.first_name}!")
    else:
        # Step 1: Send OTP
        await sdk.auth.send_otp("91", "9876543210")

        # Step 2: Verify OTP and login
        otp = input("Enter OTP: ")
        result = await sdk.login_with_phone("91", "9876543210", otp)

        if result["success"]:
            print(f"Logged in as {result['user'].first_name}")

    # Get wallet balance
    balance = await sdk.wallet.get_balance()
    print(f"Balance: {balance} $Zo")

    # Cleanup
    await sdk.close()

if __name__ == "__main__":
    asyncio.run(main())

📚 Documentation

Authentication

Send OTP

result = await sdk.auth.send_otp(
    country_code="91",
    phone_number="9876543210"
)
if result["success"]:
    print(result["message"])

Verify OTP and Login

result = await sdk.login_with_phone(
    country_code="91",
    phone_number="9876543210",
    otp="123456"
)
if result["success"]:
    user = result["user"]
    print(f"Logged in: {user.first_name}")

Check Authentication Status

if sdk.is_authenticated:
    print(f"User: {sdk.user.first_name}")
else:
    print("Not authenticated")

Logout

await sdk.logout()

Profile Management

Get Profile

token = await sdk.storage.get_item("zo_access_token")
result = await sdk.profile.get_profile(token)
if result["success"]:
    profile = result["profile"]
    print(f"Bio: {profile.bio}")

Update Profile

token = await sdk.storage.get_item("zo_access_token")
result = await sdk.profile.update_profile(
    token,
    updates={"bio": "New bio", "first_name": "Jane"}
)
if result["success"]:
    print("Profile updated!")

Avatar Generation

Generate Avatar

token = await sdk.storage.get_item("zo_access_token")
result = await sdk.avatar.generate_avatar(token, body_type="bro")  # or "bae"
if result["success"]:
    task_id = result["task_id"]
    print(f"Avatar generation started: {task_id}")

Check Avatar Status

result = await sdk.avatar.get_avatar_status(token, task_id)
if result["status"] == "completed":
    print(f"Avatar ready: {result['avatar_url']}")

Poll for Completion

await sdk.avatar.poll_avatar_status(
    token,
    task_id,
    on_progress=lambda status: print(f"Status: {status}"),
    on_complete=lambda url: print(f"Avatar: {url}"),
    on_error=lambda error: print(f"Error: {error}")
)

Wallet Operations

Get Balance

balance = await sdk.wallet.get_balance()
print(f"Balance: {balance} $Zo")

Get Transactions

result = await sdk.wallet.get_transactions(page=1)
transactions = result["transactions"]
for tx in transactions:
    print(tx)

🔧 Configuration

SDK Options

sdk = ZoPassportSDK(
    client_key="YOUR_CLIENT_KEY",           # Required: API client key
    base_url="https://api.io.zo.xyz",       # Optional: API base URL
    storage_adapter=None,                    # Optional: Custom storage adapter
    auto_refresh=True,                       # Optional: Enable auto token refresh
    refresh_interval=60000,                  # Optional: Refresh check interval (ms)
    debug=False,                             # Optional: Enable debug logging
    max_retries=3,                           # Optional: Max retry attempts
    timeout=10,                              # Optional: Request timeout (seconds)
)

Storage Adapters

File Storage (Default)

from zopassport import FileStorageAdapter

storage = FileStorageAdapter(file_path="session.json")
sdk = ZoPassportSDK(client_key="...", storage_adapter=storage)

Encrypted File Storage

from zopassport import EncryptedFileStorageAdapter

# Option 1: With password
storage = EncryptedFileStorageAdapter(
    file_path="session.enc",
    password="your-secure-password"
)

# Option 2: With key file
storage = EncryptedFileStorageAdapter(
    file_path="session.enc",
    key_file=".session_key"
)

sdk = ZoPassportSDK(client_key="...", storage_adapter=storage)

Memory Storage (Not Persistent)

from zopassport import MemoryStorageAdapter

storage = MemoryStorageAdapter()
sdk = ZoPassportSDK(client_key="...", storage_adapter=storage)

Custom Storage Adapter

from zopassport import StorageAdapter

class CustomStorage(StorageAdapter):
    async def get_item(self, key: str) -> Optional[str]:
        # Your implementation
        pass

    async def set_item(self, key: str, value: str) -> None:
        # Your implementation
        pass

    async def remove_item(self, key: str) -> None:
        # Your implementation
        pass

⚠️ Error Handling

The SDK provides specific exception types for different error scenarios:

from zopassport import (
    ZoPassportError,           # Base exception
    ZoAuthenticationError,     # Authentication failures
    ZoNetworkError,            # Network issues
    ZoRateLimitError,          # Rate limiting
    ZoValidationError,         # Invalid input
    ZoStorageError,            # Storage failures
    ZoWalletError,             # Wallet operations
)

try:
    await sdk.login_with_phone("91", "9876543210", "123456")
except ZoAuthenticationError as e:
    print(f"Auth failed: {e}")
except ZoRateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
except ZoNetworkError as e:
    print(f"Network error: {e}")
except ZoPassportError as e:
    print(f"SDK error: {e}")

🔒 Security Best Practices

1. Use Encrypted Storage

# Use password-based encryption
storage = EncryptedFileStorageAdapter(
    file_path="session.enc",
    password=os.environ["SESSION_PASSWORD"]
)

2. Store Client Key Securely

# Never hardcode credentials
client_key = os.environ.get("ZO_CLIENT_KEY")
sdk = ZoPassportSDK(client_key=client_key)

3. Handle Sensitive Data Carefully

# Don't log sensitive information
logger.setLevel("INFO")  # Avoid DEBUG in production

4. Implement Proper Session Management

# Always close SDK when done
try:
    # Your code
    pass
finally:
    await sdk.close()

5. Validate User Input

# Validate before sending to API
if not phone_number.isdigit():
    raise ValueError("Invalid phone number")

🧪 Testing

Run Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=src/zopassport --cov-report=html

# Run specific test file
pytest tests/unit/test_auth.py

# Run with verbose output
pytest -v

Run Linting

# Format code
black src/ tests/

# Lint code
ruff check src/ tests/

# Type check
mypy src/

🤝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

Development Setup

# Clone repository
git clone https://github.com/ZoHouse/zopassport.git
cd zopassport

# Install dependencies
pip install -e ".[dev]"

# Install pre-commit hooks
pre-commit install

# Run tests
pytest

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🔗 Links

💬 Support

🙏 Acknowledgments

Built with ❤️ by the Zo World Team


Note: This SDK requires Python 3.11 or higher.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zopassport-0.1.0.tar.gz (130.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zopassport-0.1.0-py3-none-any.whl (27.2 kB view details)

Uploaded Python 3

File details

Details for the file zopassport-0.1.0.tar.gz.

File metadata

  • Download URL: zopassport-0.1.0.tar.gz
  • Upload date:
  • Size: 130.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zopassport-0.1.0.tar.gz
Algorithm Hash digest
SHA256 13b77ce3ff77b9c89d55b09a16d8444fc22172634b6658b4b097aa6f92d8d55e
MD5 cef1f33dc064354ff5f6409677e889cf
BLAKE2b-256 01b9d401bd860717af64e7f685e65500acdbb925586cac57a0505c6f1e8adb36

See more details on using hashes here.

Provenance

The following attestation bundles were made for zopassport-0.1.0.tar.gz:

Publisher: publish.yml on ZoHouse/zopassport-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zopassport-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: zopassport-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zopassport-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 443168637cdd34175cd6b592b186e53f528709f8e3b3d59c181ad04e47ee57b0
MD5 fde63a6457b73b4d435b42513ec10490
BLAKE2b-256 2b20aca091ee5bfdc7e0497d30f5ab0ff3dfa95428f3c02567732207b57f3d3e

See more details on using hashes here.

Provenance

The following attestation bundles were made for zopassport-0.1.0-py3-none-any.whl:

Publisher: publish.yml on ZoHouse/zopassport-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page