Skip to main content

Pamela Enterprise Voice API SDK for Python

Project description

thisispamela SDK for Python

Official SDK for the Pamela 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 API subscription (see Subscription Requirements below)
  2. Create an API key via one of these methods:
    • Developer portal at developer.thisispamela.com: Log in and navigate to the API settings 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

API Subscription Required

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

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

Grace Period

API 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 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 API subscription required
7008 Subscription expired (grace period ended)

Validation Errors (400)

Code Description
2001 Validation error
2002 Invalid phone number format

API 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

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 API
        "project_limit": None
    }
}

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

API Reference

See the Pamela 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.4.tar.gz (16.6 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.4-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for thisispamela-1.1.4.tar.gz
Algorithm Hash digest
SHA256 afec8a44538c7f3832cd60d862c0b3ba317ae4d8ee2e5a5e9e1fff6b8bf18709
MD5 a04967413e8bca5ca106db038e9993df
BLAKE2b-256 fe748c2abfdb9b70e5e0db551f4027eeb5f0aa39d3ca1148a2ad9e5494bb232b

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for thisispamela-1.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 e3c90ecf8803be61772149150b915060fef7ad8e99fc7374c97c00b595f14b6b
MD5 c2bb6ad6ef11453a504b37f66d7c5d89
BLAKE2b-256 eaca45a223b921e76f281d62c3e6aa0656f9eee7be85b195651546dea5509c2d

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