Skip to main content

Pamela Enterprise Voice API SDK for Python

Project description

thisispamela SDK for Python

Official SDK for the Pamela Enterprise Voice API.

Installation

pip install thisispamela

Usage

Basic Example

from pamela import PamelaClient

client = PamelaClient(
    api_key="pk_live_your_api_key_here",
    base_url="https://api.thisispamela.com",  # Optional
)

# Create a call
call = client.create_call(
    to="+1234567890",
    task="Order a large pizza for delivery",
    locale="en-US",
    max_duration_seconds=299,
    voice="female",
    agent_name="Pamela",
    caller_name="John from Acme",
)

print(f"Call created: {call['id']}")

# Get call status
status = client.get_call(call["id"])
print(f"Call status: {status['status']}")

Webhook Verification

from flask import Flask, request
from pamela import verify_webhook_signature

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

@app.route("/webhooks/pamela", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Pamela-Signature")
    payload = request.json

    if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
        return {"error": "Invalid signature"}, 401

    # Handle webhook event
    print(f"Webhook event: {payload['event']}")
    print(f"Call ID: {payload['call_id']}")

    return {"status": "ok"}, 200

Tool Webhook Handler

from flask import Flask, request
from pamela import verify_webhook_signature

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

@app.route("/webhooks/pamela/tools", methods=["POST"])
def handle_tool_webhook():
    signature = request.headers.get("X-Pamela-Signature")
    payload = request.json

    if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
        return {"error": "Invalid signature"}, 401

    tool_name = payload["tool_name"]
    arguments = payload["arguments"]
    call_id = payload["call_id"]
    correlation_id = payload["correlation_id"]

    # Execute tool based on tool_name
    if tool_name == "check_order_status":
        order_id = arguments.get("order_id")
        result = check_order_status(order_id)
        return {"result": result}

    return {"error": "Unknown tool"}, 400

Getting API Keys

Obtaining Your API Key

API keys are created and managed through the Pamela Partner Portal or via the Partner API:

  1. Sign up for an Enterprise subscription (see Subscription Requirements below)
  2. Create an API key via one of these methods:
    • Partner Portal: Log in to your account and navigate to the Enterprise panel
    • Partner API: POST /api/b2b/v1/partner/api-keys
      curl -X POST https://api.thisispamela.com/api/b2b/v1/partner/api-keys \
        -H "Authorization: Bearer YOUR_B2C_USER_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"project_id": "optional-project-id", "key_prefix": "pk_live_"}'
      
  3. Save your API key immediately - the full key is only returned once during creation
  4. Use the key prefix (pk_live_) to identify keys in your account

Managing API Keys

  • List API keys: GET /api/b2b/v1/partner/api-keys
  • Revoke API key: POST /api/b2b/v1/partner/api-keys/{key_id}/revoke
  • Associate with projects: Optionally link API keys to specific projects for better organization

API Key Format

  • Live keys: Start with pk_live_ (all API usage)
  • Security: Keys are hashed in the database. Store them securely and never commit them to version control.

Subscription Requirements

Enterprise Subscription Required

All API access requires an active Enterprise subscription. API calls will return 403 Forbidden if:

  • No Enterprise subscription is active
  • Subscription status is past_due and grace period has expired
  • Subscription status is canceled

Grace Period

Enterprise subscriptions have a 1-week grace period when payment fails:

  • During grace period: API access is allowed, but usage is still charged
  • After grace period expires: API access is blocked until payment is updated

Subscription Status Endpoints

Check subscription status using the Enterprise Partner API:

  • GET /api/b2b/v1/partner/subscription - Get subscription status
  • POST /api/b2b/v1/partner/subscription/checkout - Create checkout session
  • POST /api/b2b/v1/partner/subscription/portal - Access Customer Portal

Error Handling

The SDK provides structured exceptions for all API errors:

from pamela import (
    PamelaClient,
    PamelaError,
    AuthenticationError,
    SubscriptionError,
    RateLimitError,
    ValidationError,
    CallError,
)

client = PamelaClient(api_key="pk_live_your_key")

try:
    call = client.create_call(to="+1234567890", task="Test call")
except AuthenticationError as e:
    # 401: Invalid or missing API key
    print(f"Auth failed: {e.message}")
    print(f"Error code: {e.error_code}")
except SubscriptionError as e:
    # 403: Subscription inactive or expired
    if e.error_code == 7008:
        print("Grace period expired - update payment method")
    else:
        print(f"Subscription issue: {e.message}")
except RateLimitError as e:
    # 429: Rate limit exceeded
    retry_after = e.details.get("retry_after", 30)
    print(f"Rate limited, retry after {retry_after}s")
except ValidationError as e:
    # 400/422: Invalid request parameters
    print(f"Invalid request: {e.message}")
    print(f"Details: {e.details}")
except CallError as e:
    # Call-specific errors
    print(f"Call error: {e.message}")
except PamelaError as e:
    # All other API errors
    print(f"API error {e.error_code}: {e.message}")

Exception Hierarchy

All exceptions inherit from PamelaError:

PamelaError (base)
├── AuthenticationError  # 401 errors
├── SubscriptionError    # 403 errors (subscription issues)
├── RateLimitError       # 429 errors
├── ValidationError      # 400/422 errors
└── CallError            # Call-specific errors

Exception Attributes

All exceptions have:

  • message: Human-readable error message
  • error_code: Numeric error code (e.g., 7008 for subscription expired)
  • details: Dict with additional context
  • status_code: HTTP status code

Error Codes Reference

Authentication Errors (401)

Code Description
1001 API key required
1002 Invalid API key
1003 API key expired

Subscription Errors (403)

Code Description
1005 Enterprise subscription required
7008 Subscription expired (grace period ended)

Validation Errors (400)

Code Description
2001 Validation error
2002 Invalid phone number format

Enterprise Errors (7xxx)

Code Description
7001 Partner not found
7002 Project not found
7003 Call not found
7004 No phone number for country
7005 Unsupported country

Rate Limiting (429)

Code Description
6001 Rate limit exceeded
6002 Quota exceeded

Usage Limits & Billing

Enterprise API Usage

  • Unlimited API calls (no call count limits)
  • All API usage billed at $0.10/minute (10 cents per minute)
  • Minimum billing: 1 minute per call (even if call duration < 60 seconds)
  • Billing calculation: billed_minutes = max(ceil(duration_seconds / 60), 1)
  • Only calls that connect (have started_at) are billed

Usage Tracking

  • Usage is tracked in b2b_usage collection with type: "api_usage" (collection name stays b2b_usage)
  • Usage is synced to Stripe hourly (at :00 minutes)
  • Stripe meter name: stripe_minutes
  • Failed syncs are retried with exponential backoff (1s, 2s, 4s, 8s, 16s), max 5 retries

Billing Period

  • Billing is based on calendar months (UTC midnight on 1st of each month)
  • Calls are billed in the month where started_at occurred
  • Usage sync status: pending, synced, or failed

API Methods

Calls

  • create_call(to, task, ...) - Create a new call
  • get_call(call_id) - Get call status and details
  • list_calls(status?, limit?, offset?, ...) - List calls with optional filters
  • cancel_call(call_id) - Cancel an in-progress call
  • hangup_call(call_id) - Force hangup an in-progress call

Tools

  • register_tool(name, description, input_schema, ...) - Register a tool
  • list_tools() - List all tools
  • delete_tool(tool_id) - Delete a tool

Usage

  • usage.get(period=None) - Get usage statistics

Example:

# Get current month usage
usage = client.usage.get()

# Get usage for specific period
jan_usage = client.usage.get("2024-01")

print(f"Usage: {usage['call_count']} calls, {usage.get('api_minutes', 0)} minutes")
print(f"Quota: {usage.get('quota', {}).get('partner_limit', 'Unlimited')}")

Response:

{
    "partner_id": "partner_123",
    "project_id": "project_456",  # Optional
    "period": "2024-01",
    "call_count": 150,
    "quota": {
        "partner_limit": None,  # None = unlimited for Enterprise
        "project_limit": None
    }
}

Note: Enterprise subscriptions have no quota limits - all usage is billed per-minute.

API Reference

See the Pamela Enterprise API Documentation for full API reference.

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

thisispamela-1.1.0.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

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

thisispamela-1.1.0-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file thisispamela-1.1.0.tar.gz.

File metadata

  • Download URL: thisispamela-1.1.0.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for thisispamela-1.1.0.tar.gz
Algorithm Hash digest
SHA256 ce58f3973ab5d79a236b283387e6a6516fe14cc6e36443903dc0fe767dea2da9
MD5 4e4d52784f4cd3440b786dec9e1c5e1d
BLAKE2b-256 ba48fce8d4dd29151f498a0ea47fe96f25f0157f9f45a83a39fd7f3f39f924df

See more details on using hashes here.

File details

Details for the file thisispamela-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: thisispamela-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for thisispamela-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bac472d80ec870fb239ce3bd7c21b20990b74cb17f98cebdfb418f59faed4c9f
MD5 b683984fa313673a232674e80ac16785
BLAKE2b-256 eee805e55c380e12f5c9120e61e744f3626132ec8654d0e3621d10f6d9aa83c5

See more details on using hashes here.

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