bagelpay


Namebagelpay JSON
Version 1.0.1 PyPI version JSON
download
home_pagehttps://github.com/bagelpay/bagelpay-sdk-python
SummaryBagelPay Python SDK
upload_time2025-09-15 01:15:24
maintainerNone
docs_urlNone
authorBagelPay
requires_python>=3.7
licenseNone
keywords bagelpay payment api sdk python
VCS
bugtrack_url
requirements requests typing-extensions pytest pytest-cov pytest-mock coverage black flake8 mypy twine wheel setuptools colorama tabulate
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # BagelPay Python SDK

A comprehensive Python client library for the BagelPay API, providing developers with an easy-to-use payment integration solution.

## ๐Ÿ“‹ Table of Contents

- [Quick Start](#quick-start)
- [Installation Guide](#installation-guide)
- [Basic Configuration](#basic-configuration)
- [Beginner Tutorial](#beginner-tutorial)
- [API Reference](#api-reference)
- [Example Code](#example-code)
- [Error Handling](#error-handling)
- [Testing Guide](#testing-guide)
- [Development Guide](#development-guide)
- [Advanced Usage](#advanced-usage)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)

## ๐Ÿš€ Quick Start

### 30-Second Quick Demo

```python
from bagelpay import BagelPayClient, CheckoutRequest, Customer

# 1. Initialize the client
client = BagelPayClient(
    base_url="https://test.bagelpay.io",
    api_key="your-test-api-key-here"
)

# 2. Create a payment session
from datetime import datetime

checkout_request = CheckoutRequest(
    product_id="prod_123456789",
    request_id=f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
    units="1",
    customer=Customer(
        email="customer@example.com"
    ),
    success_url="https://yoursite.com/success",
    metadata={
        "order_id": f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
    }
)

# 3. Get payment URL
response = client.create_checkout(checkout_request)
print(f"Payment URL: {response.checkout_url}")
```

## ๐Ÿ“ฆ Installation Guide

### System Requirements

- **Python**: 3.11 or higher (recommended), minimum 3.8
- **Package Manager**: pip or poetry
- **Operating System**: Windows, macOS, Linux
- **Memory**: Minimum 512MB RAM
- **Network**: Internet connection for API calls

### Method 1: Install from Source (Recommended)

```bash
# Clone the repository
git clone https://github.com/bagelpay/bagelpay-sdk-python.git
cd bagelpay-sdk-python/generated-sdks/python

# Create virtual environment
python3 -m venv venv
source venv/bin/activate  # Linux/Mac
# or venv\Scripts\activate  # Windows

# Install SDK in development mode
pip install -e .

# Verify installation
python -c "import bagelpay; print('Installation successful!')"
```

### Method 2: Install from PyPI (Coming Soon)

```bash
# Install latest stable version
pip install bagelpay-sdk

# Install specific version
pip install bagelpay-sdk==1.0.0

# Install with optional dependencies
pip install bagelpay-sdk[dev,test]
```

### Method 3: Using Poetry

```bash
# Add to your project
poetry add bagelpay-sdk

# Or add from git repository
poetry add git+https://github.com/bagelpay/bagelpay-sdk-python.git
```

### Verify Installation

```python
import bagelpay
from bagelpay import BagelPayClient

print(f"BagelPay SDK Version: {bagelpay.__version__}")
print(f"Available modules: {dir(bagelpay)}")

# Test basic functionality
try:
    client = BagelPayClient(api_key="test")
    print("โœ… SDK imported successfully")
except Exception as e:
    print(f"โŒ Import failed: {e}")
```

## โš™๏ธ Basic Configuration

### Getting API Keys

1. **Sign up**: Create account at [BagelPay Dashboard](https://dashboard.bagelpay.io)
2. **Navigate**: Go to "Developer Settings" โ†’ "API Keys"
3. **Create Key**: Generate new API key for your environment
4. **Copy**: Save your test and live keys securely
5. **Environment**: Start with test keys for development

### Environment Variables Setup

```bash
# Create .env file in your project root
echo "BAGELPAY_API_KEY=your-test-api-key-here" > .env
echo "BAGELPAY_BASE_URL=https://test.bagelpay.io" >> .env
echo "BAGELPAY_TIMEOUT=30" >> .env
echo "BAGELPAY_DEBUG=false" >> .env

# Load environment variables
export $(cat .env | xargs)

# Or use python-dotenv
pip install python-dotenv
```

### Client Initialization Options

```python
from bagelpay import BagelPayClient
import os


# Method 1: Direct parameters
client = BagelPayClient(
    base_url="https://test.bagelpay.io",
    api_key="your-api-key",
    timeout=30,  # Request timeout in seconds
)

# Method 2: Configuration dictionary
config = {
    "base_url": "https://test.bagelpay.io",
    "api_key": os.getenv("BAGELPAY_API_KEY"),
    "timeout": 30
}
client = BagelPayClient(**config)

# Method 4: Context manager (recommended for production)
with BagelPayClient(api_key="your-api-key") as client:
    # Automatically handles connection cleanup
    response = client.list_products()
    print(f"Found {response.total} products")
```

### Environment-Specific Configuration

```python
# Development environment
dev_client = BagelPayClient(
    base_url="https://test.bagelpay.io",
    api_key="test_key_xxx",
    timeout=60
)

# Staging environment
staging_client = BagelPayClient(
    base_url="https://staging.bagelpay.io",
    api_key="staging_key_xxx",
    timeout=30
)

# Production environment
production_client = BagelPayClient(
    base_url="https://api.bagelpay.io",
    api_key="live_key_xxx",
    timeout=15,
)
```

## ๐Ÿ“š Beginner Tutorial

### Step 1: Create Your First Product

```python
from bagelpay import BagelPayClient, CreateProductRequest

# Initialize client
client = BagelPayClient(api_key="your-test-api-key")

# Create a digital product
product_request = CreateProductRequest(
    name="Premium Membership",
    description="Access to all premium features with monthly billing",
    price=29.99,
    currency="USD",
    billing_type="subscription", # subscription or single_payment
    tax_inclusive=True,
    tax_category="digital_products", # digital_products, saas_services or ebooks
    recurring_interval="daily", # daily, weekly, monthly, 3months or 6months
    trial_days=1,
)

try:
    product = client.create_product(product_request)
    print(f"โœ… Product created successfully!")
    print(f"Product ID: {product.product_id}")
    print(f"Product Name: {product.name}")
    print(f"Price: ${product.price} {product.currency}")
except Exception as e:
    print(f"โŒ Failed to create product: {e}")
```

### Step 2: Create a Payment Session

```python
from bagelpay import CheckoutRequest, Customer

# Prepare customer information
customer = Customer(
    email="john.doe@example.com"
)

# Create checkout request
from datetime import datetime

checkout_request = CheckoutRequest(
    product_id=product.product_id,  # Use the product ID from step 1
    request_id=f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
    units="1",
    customer=customer,
    success_url="https://yoursite.com/success",
    metadata={
        "order_id": f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
        "user_id": "user_12345",
        "source": "web_app",
        "campaign": "summer_promotion"
    }
)

try:
    checkout_response = client.create_checkout(checkout_request)
    
    print(f"โœ… Checkout session created!")
    print(f"Payment URL: {checkout_response.checkout_url}")
    print(f"Payment ID: {checkout_response.payment_id}")
    print(f"Product ID: {checkout_response.product_id}")
    print(f"Status: {checkout_response.status}")
    print(f"Expires On: {checkout_response.expires_on}")
    
    # Store payment ID for later reference
    payment_id = checkout_response.payment_id
    
except Exception as e:
    print(f"โŒ Failed to create checkout: {e}")
```

### Step 3: Monitor Transactions

```python
# Get transaction history
try:
    transactions = client.list_transactions(pageNum=1, pageSize=20)
    
    print(f"\n๐Ÿ“Š Transaction Summary:")
    print(f"Total Transactions: {transactions.total}")
    print(f"Showing {len(transactions.items)} transactions on this page")
    print(f"Items per Page: 20")
except Exception as e:
    print(f"โŒ Failed to fetch transactions: {e}")
```

### Step 4: Manage Products

```python
# List all products
try:
    products = client.list_products(pageNum=1, pageSize=50)
    
    print(f"\n๐Ÿ›๏ธ Product Catalog ({products.total} total):")
    
    for product in products.items:
        status = "๐ŸŸข Active" if not product.is_archive else "๐Ÿ”ด Archived"
        print(f"\n{status} {product.name}")
        print(f"   ID: {product.product_id}")
        if product.recurring_interval:
            print(f"   Price: ${product.price} {product.currency}/{product.recurring_interval}")
        else:
            print(f"   Price: ${product.price} {product.currency}")
        print(f"   Type: {product.billing_type}")
        print(f"   Created: {product.created_at}")
    
    # Update a product
    if products.items:
        first_product = products.items[0]
        
        from bagelpay import UpdateProductRequest
        import random
        
        update_request = UpdateProductRequest(
            product_id=first_product.product_id,
            name="New_Product_" + str(random.randint(1000, 9999)),
            description="New_Description_of_product_" + str(random.randint(1000, 9999)),
            price=random.uniform(50.5, 1024.5),
            currency="USD",
            billing_type=random.choice(["subscription", "subscription", "single_payment"]),
            tax_inclusive=False,
            tax_category=random.choice(["digital_products", "saas_services", "ebooks"]),
            recurring_interval=random.choice(["daily", "weekly", "monthly", "3months", "6months"]),
            trial_days=random.choice([0, 1, 7])
        )
        
        updated_product = client.update_product(update_request)
        print(f"\nโœ… Updated product: {updated_product.name}")
        print(f"   New price: ${updated_product.price}")
        
except Exception as e:
    print(f"โŒ Failed to manage products: {e}")
```

## ๐Ÿ”ง API Reference

### Product Management API

#### Creating Products

```python
# One-time payment product
one_time_product = CreateProductRequest(
    name="E-book: Python Programming Guide",
    description="Comprehensive guide to Python programming",
    price=49.99,
    currency="USD",
    billing_type="single_payment",
    tax_inclusive=False,
    tax_category="digital_products",
    recurring_interval="none",
    trial_days=0
)

# Subscription product
subscription_product = CreateProductRequest(
    name="Monthly Pro Plan",
    description="Professional features with monthly billing",
    price=19.99,
    currency="USD",
    billing_type="subscription",
    tax_inclusive=True,
    tax_category="digital_products",
    recurring_interval="monthly",
    trial_days=14
)
```

#### Product Operations

```python
# Get product details
product = client.get_product("prod_123456")
print(f"Product: {product.name}")
print(f"Status: {'Active' if not product.is_archive else 'Archived'}")

# Archive product (stop selling but keep records)
archived_product = client.archive_product("prod_123456")
print(f"Product archived: {archived_product.is_archive}")

# Unarchive product
unarchived_product = client.unarchive_product("prod_123456")
print(f"Product restored: {not unarchived_product.is_archive}")

# Bulk product operations
all_products = []
page_num = 1
while True:
    products = client.list_products(pageNum=page_num, pageSize=100)
    all_products.extend(products.items)
    
    if len(products.items) < 100:
        break
    page_num += 1

print(f"Total products loaded: {len(all_products)}")

# Filter products by criteria
active_products = [p for p in all_products if not p.is_archive]
subscription_products = [p for p in all_products if p.billing_type == "subscription"]
expensive_products = [p for p in all_products if p.price > 100]

print(f"Active products: {len(active_products)}")
print(f"Subscription products: {len(subscription_products)}")
print(f"Premium products (>$100): {len(expensive_products)}")
```

### Payment Session API

#### Advanced Checkout Configuration

```python
# Comprehensive checkout request
from datetime import datetime

advanced_checkout = CheckoutRequest(
    product_id="prod_premium_plan",
    request_id=f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
    units="3",
    customer=Customer(
        email="premium.user@company.com"
    ),
    success_url="https://yoursite.com/success",
    metadata={
        # Campaign tracking
        "order_id": f"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
        "campaign_id": "black_friday_2024",
        "discount_code": "SAVE30",
        "affiliate_id": "partner_123",
        
        # User context
        "user_id": "user_789",
        "user_tier": "enterprise",
        "company": "Tech Corp Inc",
        
        # Analytics
        "source": "landing_page",
        "medium": "organic",
        "referrer": "https://google.com",
        "utm_campaign": "product_launch"
    }
)

response = client.create_checkout(advanced_checkout)

# Extract detailed checkout information
print(f"\n๐Ÿ’ณ Checkout Session Created:")
print(f"Payment ID: {response.payment_id}")
print(f"Checkout URL: {response.checkout_url}")
print(f"Product ID: {response.product_id}")
print(f"Status: {response.status}")
print(f"Expires On: {response.expires_on}")
print(f"Success URL: {response.success_url}")
```


### Subscription Management API

```python
# Comprehensive subscription management
def manage_subscriptions(client):
    """Manage customer subscriptions"""
    try:
        subscriptions = client.list_subscriptions(pageNum=1, pageSize=100)
        
        print(f"\n๐Ÿ”„ Subscription Management ({subscriptions.total} total):")
        
        active_subs = []
        cancelled_subs = []
        paused_subs = []
        trialing_subs = []
        
        for subscription in subscriptions.items:
            print(f"\n๐Ÿ“‹ Subscription: {subscription.subscription_id}")
            print(f"   Status: {subscription.status}")
            print(f"   Customer: {subscription.customer}")
            print(f"   Product: {subscription.product_name}")
            print(f"   Next Billing: {subscription.billing_period_end}")
            print(f"   Next Billing Amount: ${subscription.next_billing_amount}")
            
            if subscription.status == "active":
                active_subs.append(subscription)
            elif subscription.status == "canceled":
                cancelled_subs.append(subscription)
            elif subscription.status == "paused":
                paused_subs.append(subscription)
            elif subscription.status == "trialing":
                trialing_subs.append(subscription)

        print(f"\n๐Ÿ“ˆ Subscription Summary:")
        print(f"Active: {len(active_subs)}")
        print(f"Cancelled: {len(cancelled_subs)}")
        print(f"Paused: {len(paused_subs)}")
        print(f"Trialing: {len(trialing_subs)}")
        
        # Calculate MRR (Monthly Recurring Revenue)
        monthly_revenue = sum(
            sub.next_billing_amount for sub in active_subs 
            if sub.recurring_interval == "monthly"
        )
        annual_revenue = sum(
            sub.next_billing_amount / 12 for sub in active_subs 
            if sub.recurring_interval == "yearly"
        )
        total_mrr = monthly_revenue + annual_revenue
        
        print(f"๐Ÿ’ฐ Monthly Recurring Revenue: ${total_mrr:.2f}")
        
        return {
            "active": len(active_subs),
            "cancelled": len(cancelled_subs),
            "paused_subs": len(paused_subs),
            "trialing_subs": len(trialing_subs),
            "mrr": total_mrr
        }
        
    except Exception as e:
        print(f"โŒ Error managing subscriptions: {e}")
        return None

# Cancel subscription with reason
def cancel_subscription_with_reason(client, subscription_id):
    """Cancel subscription with cancellation reason"""
    try:
        # Note: This assumes the SDK supports cancellation reasons
        result = client.cancel_subscription(
            subscription_id,
        )
        print(f"โœ… Subscription {subscription_id} cancelled")
        return result
    except Exception as e:
        print(f"โŒ Failed to cancel subscription: {e}")
        return None

manage_subscriptions(client)
cancel_subscription_with_reason(client, "sub_1966676965965533186")
```


## ๐Ÿ’ก Example Code

The SDK includes comprehensive examples in the `examples/` directory:

### Available Examples

| File | Description | Use Case | Complexity |
|------|-------------|----------|------------|
| `basic_usage.py` | Basic SDK functionality | Getting started | Beginner |
| `checkout_payments.py` | Complete payment flow | E-commerce integration | Intermediate |
| `product_management.py` | Product CRUD operations | Catalog management | Intermediate |
| `subscription_customer_management.py` | Subscription & customer ops | SaaS applications | Advanced |

### Running Examples

```bash
# Set up environment
export BAGELPAY_API_KEY="your-test-api-key"
export BAGELPAY_BASE_URL="https://test.bagelpay.io"

# Run basic example
python examples/basic_usage.py

# Run with verbose output
BAGELPAY_DEBUG=true python examples/checkout_payments.py
```


## โš ๏ธ Error Handling

### Exception Hierarchy

```python
from bagelpay.exceptions import (
    BagelPayError,              # Base exception class
    BagelPayAPIError,           # API-related errors
    BagelPayAuthenticationError, # Authentication failures
    BagelPayValidationError,    # Request validation errors
    BagelPayNotFoundError,      # Resource not found
    BagelPayRateLimitError,     # Rate limiting
    BagelPayNetworkError,       # Network connectivity issues
    BagelPayTimeoutError        # Request timeout
)

# Exception hierarchy:
# BagelPayError
# โ”œโ”€โ”€ BagelPayAPIError
# โ”‚   โ”œโ”€โ”€ BagelPayAuthenticationError
# โ”‚   โ”œโ”€โ”€ BagelPayValidationError
# โ”‚   โ”œโ”€โ”€ BagelPayNotFoundError
# โ”‚   โ””โ”€โ”€ BagelPayRateLimitError
# โ”œโ”€โ”€ BagelPayNetworkError
# โ””โ”€โ”€ BagelPayTimeoutError
```

## ๐Ÿงช Testing Guide

### Test Suite Overview

The SDK includes a comprehensive test suite with multiple testing strategies:

```bash
# Test runner with all options
python run_tests.py --help

# Basic test execution
python run_tests.py                    # Run all tests
python run_tests.py --unit             # Unit tests only
python run_tests.py --integration      # Integration tests only
python run_tests.py --mock             # Mock mode (no real API calls)
python run_tests.py --coverage         # Generate coverage report
python run_tests.py --fast             # Parallel execution
python run_tests.py --verbose          # Detailed output
```

### Test Configuration

```bash
# Environment setup for testing
export BAGELPAY_API_KEY="test_key_12345"
export BAGELPAY_BASE_URL="https://test.bagelpay.io"
export BAGELPAY_TEST_MODE="true"
export BAGELPAY_DEBUG="false"

# Install test dependencies
pip install pytest pytest-mock pytest-cov pytest-xdist responses

# Or use the setup command
python run_tests.py --setup
```


### Project Structure

```
bagelpay-sdk-python/
โ”œโ”€โ”€ bagelpay/      # Main SDK package
โ”‚   โ”œโ”€โ”€ __init__.py         # Package initialization
โ”‚   โ”œโ”€โ”€ client.py           # Main client class
โ”‚   โ”œโ”€โ”€ models.py           # Data models
โ”‚   โ”œโ”€โ”€ exceptions.py       # Custom exceptions
โ”‚   โ””โ”€โ”€ utils.py            # Utility functions
โ”œโ”€โ”€ examples/               # Example scripts
โ”‚   โ”œโ”€โ”€ basic_usage.py      # Basic functionality
โ”‚   โ”œโ”€โ”€ checkout_payments.py # Payment processing
โ”‚   โ”œโ”€โ”€ product_management.py # Product operations
โ”‚   โ””โ”€โ”€ subscription_customer_management.py # Advanced features
โ”œโ”€โ”€ tests/                  # Test suite
โ”‚   โ”œโ”€โ”€ conftest.py         # Test configuration
โ”‚   โ”œโ”€โ”€ test_client.py      # Client tests
โ”‚   โ”œโ”€โ”€ test_models.py      # Model tests
โ”‚   โ”œโ”€โ”€ test_exceptions.py  # Exception tests
โ”‚   โ””โ”€โ”€ test_integration.py # Integration tests
โ”œโ”€โ”€ docs/                   # Documentation
โ”œโ”€โ”€ requirements.txt        # Dependencies
โ”œโ”€โ”€ setup.py               # Package setup
โ”œโ”€โ”€ run_tests.py           # Test runner
โ”œโ”€โ”€ pytest.ini            # Pytest configuration
โ””โ”€โ”€ README.md              # This file
```

### Contributing Guidelines

1. **Fork and Clone**
   ```bash
   git fork https://github.com/bagelpay/bagelpay-sdk-python.git
   git clone https://github.com/yourusername/bagelpay-sdk-python.git
   ```

2. **Create Feature Branch**
   ```bash
   git checkout -b feature/amazing-new-feature
   ```

3. **Make Changes**
   - Follow existing code style
   - Add tests for new functionality
   - Update documentation
   - Ensure all tests pass

4. **Quality Checks**
   ```bash
   # Run all tests
   python run_tests.py --coverage
   
   # Code quality
   black bagelpay/
   flake8 bagelpay/
   mypy bagelpay/
   ```

5. **Commit and Push**
   ```bash
   git add .
   git commit -m "feat: add amazing new feature"
   git push origin feature/amazing-new-feature
   ```

6. **Create Pull Request**
   - Provide clear description
   - Include test results
   - Reference related issues


## ๐Ÿš€ Webhook Integration

```python
import hmac
import hashlib
import json

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
from pyngrok import ngrok
ngrok.set_auth_token("your_ngrok_key")
WEBHOOK_SECRET = "your_webhook_key"

app = FastAPI()


def verify_webhook_signature(signature_data: bytes, signature: str, secret: str) -> bool:
    """Verify webhook signature for security"""
    expected_signature = hmac.new(
        secret.encode('utf-8'),
        signature_data,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected_signature, signature)


@app.post("/api/webhooks")
async def handle_post(request: Request):
    """Handle BagelPay webhook notifications"""
    payload = await request.body()
    timestamp = request.headers.get('timestamp').encode()
    signature = request.headers.get('bagelpay_signature')
    # Combine payload and timestamp
    signature_data = timestamp + ".".encode() + payload

    if not verify_webhook_signature(signature_data, signature, WEBHOOK_SECRET):
        return JSONResponse(status_code=401, content={"error": "Invalid signature"})

    try:
        event = json.loads(payload)
        event_type = event.get('event_type')
        data = event.get('object')

        if event_type == 'checkout.completed':
            # handle checkout completed events
            print(event)
        elif event_type == 'checkout.failed':
            # handle checkout failed events
            print(event)
        elif event_type == 'checkout.cancel':
            # handle checkout cancelled events
            print(event)
        elif event_type == 'subscription.trialing':
            # handle subscription trialing events
            print(event)
        elif event_type == 'subscription.paid':
            # handle subscription paid events
            print(event)
        elif event_type == 'subscription.canceled':
            # handle subscription cancelled events
            print(event)
        elif event_type == 'refund.created':
            # handle refund created events
            print(event)
        else:
            print(f"Unhandled event type: {event_type}")

        return JSONResponse(status_code=200, content={"message": "Success"})
    except Exception as e:
        print(f"Webhook processing error: {e}")
        return JSONResponse(status_code=500, content={"error": "Processing failed"})


if __name__ == "__main__":
    listening_port = "8000"
    public_url = ngrok.connect(
        addr=listening_port,
        proto="http",
        hostname="stunning-crane-direct.ngrok-free.app"
    )
    print(f"ngrok Public URL: {public_url}")
    uvicorn.run(app, host="0.0.0.0", port=int(listening_port))
```


## โ“ FAQ

### General Questions

**Q: What Python versions are supported?**

A: The SDK supports Python 3.8+ with the following recommendations:
- **Recommended**: Python 3.11 or higher
- **Minimum**: Python 3.8
- **Tested on**: Python 3.8, 3.9, 3.10, 3.11, 3.12

**Q: How do I switch between test and production environments?**

```python
# Test environment
test_client = BagelPayClient(
    base_url="https://test.bagelpay.io",
    api_key="test_key_xxx"
)

# Production environment
prod_client = BagelPayClient(
    base_url="https://live.bagelpay.io",
    api_key="live_key_xxx"
)
```

**Q: How do I handle webhook verification?**

```python
import hmac
import hashlib

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
from pyngrok import ngrok
ngrok.set_auth_token("your_ngrok_key")
WEBHOOK_SECRET = "your_webhook_key"

app = FastAPI()


def verify_webhook_signature(signature_data: bytes, signature: str, secret: str) -> bool:
    """Verify webhook signature for security"""
    expected_signature = hmac.new(
        secret.encode('utf-8'),
        signature_data,
        hashlib.sha256
    ).hexdigest()

    print("expected_signature: ", expected_signature)
    print("signature: ", signature)

    return hmac.compare_digest(expected_signature, signature)


@app.post("/api/webhooks")
async def handle_post(request: Request):
    """Handle BagelPay webhook notifications"""
    payload = await request.body()
    timestamp = request.headers.get('timestamp').encode()
    signature = request.headers.get('bagelpay_signature')
    # Combine payload and timestamp
    signature_data = timestamp + ".".encode() + payload
    print("payload: ", payload)
    print("timestamp: ", timestamp)
    print("signature: ", signature)
    print("signature_data: ", signature_data)

    if not verify_webhook_signature(signature_data, signature, WEBHOOK_SECRET):
        return JSONResponse(status_code=401, content={"error": "Invalid signature"})

    print(payload)
    return JSONResponse(status_code=200, content={"message": "Success"})


if __name__ == "__main__":
    listening_port = "8000"
    public_url = ngrok.connect(
        addr=listening_port,
        proto="http",
        hostname="stunning-crane-direct.ngrok-free.app"
    )
    print(f"ngrok Public URL: {public_url}")
    uvicorn.run(app, host="0.0.0.0", port=int(listening_port))
```


### Integration Questions

**Q: How do I integrate with popular web frameworks?**

**Flask Integration:**
```python
from flask import Flask, request, jsonify
from bagelpay import BagelPayClient

app = Flask(__name__)
client = BagelPayClient(api_key=os.getenv('BAGELPAY_API_KEY'))

@app.route('/create-payment', methods=['POST'])
def create_payment():
    try:
        data = request.get_json()
        
        checkout_request = CheckoutRequest(...)
        response = client.create_checkout(checkout_request)
        
        return jsonify({
            'success': True,
            'payment_url': response.data.checkout_url,
            'payment_id': response.data.payment_id
        })
        
    except Exception as e:
        return jsonify({
            'success': False,
            'error': str(e)
        }), 400
```

**Django Integration:**
```python
# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import json

@csrf_exempt
@require_http_methods(["POST"])
def create_payment(request):
    try:
        data = json.loads(request.body)
        
        # Use your BagelPay client here
        checkout_request = CheckoutRequest(...)
        response = client.create_checkout(checkout_request)
        
        return JsonResponse({
            'success': True,
            'payment_url': response.data.checkout_url
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e)
        }, status=400)
```


## ๐Ÿ“ž Support and Resources

### Getting Help

- ๐Ÿ“– **Official Documentation**: [https://bagelpay.gitbook.io/docs](https://bagelpay.gitbook.io/docs)
- ๐Ÿ“ง **Technical Support**: support@bagelpayment.com
- ๐Ÿ› **Bug Reports**: [GitHub Issues](https://github.com/bagelpay/bagelpay-sdk-python/issues)


## ๐Ÿ“„ License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## ๐Ÿ”— Related Links

- [BagelPay Website](https://bagelpay.io)
- [API Documentation](https://bagelpay.gitbook.io/docs/apireference)
- [Developer Dashboard](https://bagelpay.io/dashboard)
- [Privacy Policy](https://bagelpay.io/privacy)
- [Terms of Service](https://bagelpay.io/terms)

---

**Start building with BagelPay SDK and make payment integration simple!** ๐ŸŽ‰

*For the latest updates and announcements, follow us on [Twitter](https://x.com/BagelPay) and [LinkedIn](https://www.linkedin.com/company/bagel-payment).*

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/bagelpay/bagelpay-sdk-python",
    "name": "bagelpay",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "bagelpay, payment, api, sdk, python",
    "author": "BagelPay",
    "author_email": "BagelPay <support@bagelpayment.com>",
    "download_url": "https://files.pythonhosted.org/packages/6c/a1/bbe460aa002075f9e2d080a342a40c30168705e26e812b652554bcd667b2/bagelpay-1.0.1.tar.gz",
    "platform": null,
    "description": "# BagelPay Python SDK\n\nA comprehensive Python client library for the BagelPay API, providing developers with an easy-to-use payment integration solution.\n\n## \ud83d\udccb Table of Contents\n\n- [Quick Start](#quick-start)\n- [Installation Guide](#installation-guide)\n- [Basic Configuration](#basic-configuration)\n- [Beginner Tutorial](#beginner-tutorial)\n- [API Reference](#api-reference)\n- [Example Code](#example-code)\n- [Error Handling](#error-handling)\n- [Testing Guide](#testing-guide)\n- [Development Guide](#development-guide)\n- [Advanced Usage](#advanced-usage)\n- [Best Practices](#best-practices)\n- [Troubleshooting](#troubleshooting)\n- [FAQ](#faq)\n\n## \ud83d\ude80 Quick Start\n\n### 30-Second Quick Demo\n\n```python\nfrom bagelpay import BagelPayClient, CheckoutRequest, Customer\n\n# 1. Initialize the client\nclient = BagelPayClient(\n    base_url=\"https://test.bagelpay.io\",\n    api_key=\"your-test-api-key-here\"\n)\n\n# 2. Create a payment session\nfrom datetime import datetime\n\ncheckout_request = CheckoutRequest(\n    product_id=\"prod_123456789\",\n    request_id=f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\",\n    units=\"1\",\n    customer=Customer(\n        email=\"customer@example.com\"\n    ),\n    success_url=\"https://yoursite.com/success\",\n    metadata={\n        \"order_id\": f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\"\n    }\n)\n\n# 3. Get payment URL\nresponse = client.create_checkout(checkout_request)\nprint(f\"Payment URL: {response.checkout_url}\")\n```\n\n## \ud83d\udce6 Installation Guide\n\n### System Requirements\n\n- **Python**: 3.11 or higher (recommended), minimum 3.8\n- **Package Manager**: pip or poetry\n- **Operating System**: Windows, macOS, Linux\n- **Memory**: Minimum 512MB RAM\n- **Network**: Internet connection for API calls\n\n### Method 1: Install from Source (Recommended)\n\n```bash\n# Clone the repository\ngit clone https://github.com/bagelpay/bagelpay-sdk-python.git\ncd bagelpay-sdk-python/generated-sdks/python\n\n# Create virtual environment\npython3 -m venv venv\nsource venv/bin/activate  # Linux/Mac\n# or venv\\Scripts\\activate  # Windows\n\n# Install SDK in development mode\npip install -e .\n\n# Verify installation\npython -c \"import bagelpay; print('Installation successful!')\"\n```\n\n### Method 2: Install from PyPI (Coming Soon)\n\n```bash\n# Install latest stable version\npip install bagelpay-sdk\n\n# Install specific version\npip install bagelpay-sdk==1.0.0\n\n# Install with optional dependencies\npip install bagelpay-sdk[dev,test]\n```\n\n### Method 3: Using Poetry\n\n```bash\n# Add to your project\npoetry add bagelpay-sdk\n\n# Or add from git repository\npoetry add git+https://github.com/bagelpay/bagelpay-sdk-python.git\n```\n\n### Verify Installation\n\n```python\nimport bagelpay\nfrom bagelpay import BagelPayClient\n\nprint(f\"BagelPay SDK Version: {bagelpay.__version__}\")\nprint(f\"Available modules: {dir(bagelpay)}\")\n\n# Test basic functionality\ntry:\n    client = BagelPayClient(api_key=\"test\")\n    print(\"\u2705 SDK imported successfully\")\nexcept Exception as e:\n    print(f\"\u274c Import failed: {e}\")\n```\n\n## \u2699\ufe0f Basic Configuration\n\n### Getting API Keys\n\n1. **Sign up**: Create account at [BagelPay Dashboard](https://dashboard.bagelpay.io)\n2. **Navigate**: Go to \"Developer Settings\" \u2192 \"API Keys\"\n3. **Create Key**: Generate new API key for your environment\n4. **Copy**: Save your test and live keys securely\n5. **Environment**: Start with test keys for development\n\n### Environment Variables Setup\n\n```bash\n# Create .env file in your project root\necho \"BAGELPAY_API_KEY=your-test-api-key-here\" > .env\necho \"BAGELPAY_BASE_URL=https://test.bagelpay.io\" >> .env\necho \"BAGELPAY_TIMEOUT=30\" >> .env\necho \"BAGELPAY_DEBUG=false\" >> .env\n\n# Load environment variables\nexport $(cat .env | xargs)\n\n# Or use python-dotenv\npip install python-dotenv\n```\n\n### Client Initialization Options\n\n```python\nfrom bagelpay import BagelPayClient\nimport os\n\n\n# Method 1: Direct parameters\nclient = BagelPayClient(\n    base_url=\"https://test.bagelpay.io\",\n    api_key=\"your-api-key\",\n    timeout=30,  # Request timeout in seconds\n)\n\n# Method 2: Configuration dictionary\nconfig = {\n    \"base_url\": \"https://test.bagelpay.io\",\n    \"api_key\": os.getenv(\"BAGELPAY_API_KEY\"),\n    \"timeout\": 30\n}\nclient = BagelPayClient(**config)\n\n# Method 4: Context manager (recommended for production)\nwith BagelPayClient(api_key=\"your-api-key\") as client:\n    # Automatically handles connection cleanup\n    response = client.list_products()\n    print(f\"Found {response.total} products\")\n```\n\n### Environment-Specific Configuration\n\n```python\n# Development environment\ndev_client = BagelPayClient(\n    base_url=\"https://test.bagelpay.io\",\n    api_key=\"test_key_xxx\",\n    timeout=60\n)\n\n# Staging environment\nstaging_client = BagelPayClient(\n    base_url=\"https://staging.bagelpay.io\",\n    api_key=\"staging_key_xxx\",\n    timeout=30\n)\n\n# Production environment\nproduction_client = BagelPayClient(\n    base_url=\"https://api.bagelpay.io\",\n    api_key=\"live_key_xxx\",\n    timeout=15,\n)\n```\n\n## \ud83d\udcda Beginner Tutorial\n\n### Step 1: Create Your First Product\n\n```python\nfrom bagelpay import BagelPayClient, CreateProductRequest\n\n# Initialize client\nclient = BagelPayClient(api_key=\"your-test-api-key\")\n\n# Create a digital product\nproduct_request = CreateProductRequest(\n    name=\"Premium Membership\",\n    description=\"Access to all premium features with monthly billing\",\n    price=29.99,\n    currency=\"USD\",\n    billing_type=\"subscription\", # subscription or single_payment\n    tax_inclusive=True,\n    tax_category=\"digital_products\", # digital_products, saas_services or ebooks\n    recurring_interval=\"daily\", # daily, weekly, monthly, 3months or 6months\n    trial_days=1,\n)\n\ntry:\n    product = client.create_product(product_request)\n    print(f\"\u2705 Product created successfully!\")\n    print(f\"Product ID: {product.product_id}\")\n    print(f\"Product Name: {product.name}\")\n    print(f\"Price: ${product.price} {product.currency}\")\nexcept Exception as e:\n    print(f\"\u274c Failed to create product: {e}\")\n```\n\n### Step 2: Create a Payment Session\n\n```python\nfrom bagelpay import CheckoutRequest, Customer\n\n# Prepare customer information\ncustomer = Customer(\n    email=\"john.doe@example.com\"\n)\n\n# Create checkout request\nfrom datetime import datetime\n\ncheckout_request = CheckoutRequest(\n    product_id=product.product_id,  # Use the product ID from step 1\n    request_id=f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\",\n    units=\"1\",\n    customer=customer,\n    success_url=\"https://yoursite.com/success\",\n    metadata={\n        \"order_id\": f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\",\n        \"user_id\": \"user_12345\",\n        \"source\": \"web_app\",\n        \"campaign\": \"summer_promotion\"\n    }\n)\n\ntry:\n    checkout_response = client.create_checkout(checkout_request)\n    \n    print(f\"\u2705 Checkout session created!\")\n    print(f\"Payment URL: {checkout_response.checkout_url}\")\n    print(f\"Payment ID: {checkout_response.payment_id}\")\n    print(f\"Product ID: {checkout_response.product_id}\")\n    print(f\"Status: {checkout_response.status}\")\n    print(f\"Expires On: {checkout_response.expires_on}\")\n    \n    # Store payment ID for later reference\n    payment_id = checkout_response.payment_id\n    \nexcept Exception as e:\n    print(f\"\u274c Failed to create checkout: {e}\")\n```\n\n### Step 3: Monitor Transactions\n\n```python\n# Get transaction history\ntry:\n    transactions = client.list_transactions(pageNum=1, pageSize=20)\n    \n    print(f\"\\n\ud83d\udcca Transaction Summary:\")\n    print(f\"Total Transactions: {transactions.total}\")\n    print(f\"Showing {len(transactions.items)} transactions on this page\")\n    print(f\"Items per Page: 20\")\nexcept Exception as e:\n    print(f\"\u274c Failed to fetch transactions: {e}\")\n```\n\n### Step 4: Manage Products\n\n```python\n# List all products\ntry:\n    products = client.list_products(pageNum=1, pageSize=50)\n    \n    print(f\"\\n\ud83d\udecd\ufe0f Product Catalog ({products.total} total):\")\n    \n    for product in products.items:\n        status = \"\ud83d\udfe2 Active\" if not product.is_archive else \"\ud83d\udd34 Archived\"\n        print(f\"\\n{status} {product.name}\")\n        print(f\"   ID: {product.product_id}\")\n        if product.recurring_interval:\n            print(f\"   Price: ${product.price} {product.currency}/{product.recurring_interval}\")\n        else:\n            print(f\"   Price: ${product.price} {product.currency}\")\n        print(f\"   Type: {product.billing_type}\")\n        print(f\"   Created: {product.created_at}\")\n    \n    # Update a product\n    if products.items:\n        first_product = products.items[0]\n        \n        from bagelpay import UpdateProductRequest\n        import random\n        \n        update_request = UpdateProductRequest(\n            product_id=first_product.product_id,\n            name=\"New_Product_\" + str(random.randint(1000, 9999)),\n            description=\"New_Description_of_product_\" + str(random.randint(1000, 9999)),\n            price=random.uniform(50.5, 1024.5),\n            currency=\"USD\",\n            billing_type=random.choice([\"subscription\", \"subscription\", \"single_payment\"]),\n            tax_inclusive=False,\n            tax_category=random.choice([\"digital_products\", \"saas_services\", \"ebooks\"]),\n            recurring_interval=random.choice([\"daily\", \"weekly\", \"monthly\", \"3months\", \"6months\"]),\n            trial_days=random.choice([0, 1, 7])\n        )\n        \n        updated_product = client.update_product(update_request)\n        print(f\"\\n\u2705 Updated product: {updated_product.name}\")\n        print(f\"   New price: ${updated_product.price}\")\n        \nexcept Exception as e:\n    print(f\"\u274c Failed to manage products: {e}\")\n```\n\n## \ud83d\udd27 API Reference\n\n### Product Management API\n\n#### Creating Products\n\n```python\n# One-time payment product\none_time_product = CreateProductRequest(\n    name=\"E-book: Python Programming Guide\",\n    description=\"Comprehensive guide to Python programming\",\n    price=49.99,\n    currency=\"USD\",\n    billing_type=\"single_payment\",\n    tax_inclusive=False,\n    tax_category=\"digital_products\",\n    recurring_interval=\"none\",\n    trial_days=0\n)\n\n# Subscription product\nsubscription_product = CreateProductRequest(\n    name=\"Monthly Pro Plan\",\n    description=\"Professional features with monthly billing\",\n    price=19.99,\n    currency=\"USD\",\n    billing_type=\"subscription\",\n    tax_inclusive=True,\n    tax_category=\"digital_products\",\n    recurring_interval=\"monthly\",\n    trial_days=14\n)\n```\n\n#### Product Operations\n\n```python\n# Get product details\nproduct = client.get_product(\"prod_123456\")\nprint(f\"Product: {product.name}\")\nprint(f\"Status: {'Active' if not product.is_archive else 'Archived'}\")\n\n# Archive product (stop selling but keep records)\narchived_product = client.archive_product(\"prod_123456\")\nprint(f\"Product archived: {archived_product.is_archive}\")\n\n# Unarchive product\nunarchived_product = client.unarchive_product(\"prod_123456\")\nprint(f\"Product restored: {not unarchived_product.is_archive}\")\n\n# Bulk product operations\nall_products = []\npage_num = 1\nwhile True:\n    products = client.list_products(pageNum=page_num, pageSize=100)\n    all_products.extend(products.items)\n    \n    if len(products.items) < 100:\n        break\n    page_num += 1\n\nprint(f\"Total products loaded: {len(all_products)}\")\n\n# Filter products by criteria\nactive_products = [p for p in all_products if not p.is_archive]\nsubscription_products = [p for p in all_products if p.billing_type == \"subscription\"]\nexpensive_products = [p for p in all_products if p.price > 100]\n\nprint(f\"Active products: {len(active_products)}\")\nprint(f\"Subscription products: {len(subscription_products)}\")\nprint(f\"Premium products (>$100): {len(expensive_products)}\")\n```\n\n### Payment Session API\n\n#### Advanced Checkout Configuration\n\n```python\n# Comprehensive checkout request\nfrom datetime import datetime\n\nadvanced_checkout = CheckoutRequest(\n    product_id=\"prod_premium_plan\",\n    request_id=f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\",\n    units=\"3\",\n    customer=Customer(\n        email=\"premium.user@company.com\"\n    ),\n    success_url=\"https://yoursite.com/success\",\n    metadata={\n        # Campaign tracking\n        \"order_id\": f\"req_{datetime.now().strftime('%Y%m%d_%H%M%S')}\",\n        \"campaign_id\": \"black_friday_2024\",\n        \"discount_code\": \"SAVE30\",\n        \"affiliate_id\": \"partner_123\",\n        \n        # User context\n        \"user_id\": \"user_789\",\n        \"user_tier\": \"enterprise\",\n        \"company\": \"Tech Corp Inc\",\n        \n        # Analytics\n        \"source\": \"landing_page\",\n        \"medium\": \"organic\",\n        \"referrer\": \"https://google.com\",\n        \"utm_campaign\": \"product_launch\"\n    }\n)\n\nresponse = client.create_checkout(advanced_checkout)\n\n# Extract detailed checkout information\nprint(f\"\\n\ud83d\udcb3 Checkout Session Created:\")\nprint(f\"Payment ID: {response.payment_id}\")\nprint(f\"Checkout URL: {response.checkout_url}\")\nprint(f\"Product ID: {response.product_id}\")\nprint(f\"Status: {response.status}\")\nprint(f\"Expires On: {response.expires_on}\")\nprint(f\"Success URL: {response.success_url}\")\n```\n\n\n### Subscription Management API\n\n```python\n# Comprehensive subscription management\ndef manage_subscriptions(client):\n    \"\"\"Manage customer subscriptions\"\"\"\n    try:\n        subscriptions = client.list_subscriptions(pageNum=1, pageSize=100)\n        \n        print(f\"\\n\ud83d\udd04 Subscription Management ({subscriptions.total} total):\")\n        \n        active_subs = []\n        cancelled_subs = []\n        paused_subs = []\n        trialing_subs = []\n        \n        for subscription in subscriptions.items:\n            print(f\"\\n\ud83d\udccb Subscription: {subscription.subscription_id}\")\n            print(f\"   Status: {subscription.status}\")\n            print(f\"   Customer: {subscription.customer}\")\n            print(f\"   Product: {subscription.product_name}\")\n            print(f\"   Next Billing: {subscription.billing_period_end}\")\n            print(f\"   Next Billing Amount: ${subscription.next_billing_amount}\")\n            \n            if subscription.status == \"active\":\n                active_subs.append(subscription)\n            elif subscription.status == \"canceled\":\n                cancelled_subs.append(subscription)\n            elif subscription.status == \"paused\":\n                paused_subs.append(subscription)\n            elif subscription.status == \"trialing\":\n                trialing_subs.append(subscription)\n\n        print(f\"\\n\ud83d\udcc8 Subscription Summary:\")\n        print(f\"Active: {len(active_subs)}\")\n        print(f\"Cancelled: {len(cancelled_subs)}\")\n        print(f\"Paused: {len(paused_subs)}\")\n        print(f\"Trialing: {len(trialing_subs)}\")\n        \n        # Calculate MRR (Monthly Recurring Revenue)\n        monthly_revenue = sum(\n            sub.next_billing_amount for sub in active_subs \n            if sub.recurring_interval == \"monthly\"\n        )\n        annual_revenue = sum(\n            sub.next_billing_amount / 12 for sub in active_subs \n            if sub.recurring_interval == \"yearly\"\n        )\n        total_mrr = monthly_revenue + annual_revenue\n        \n        print(f\"\ud83d\udcb0 Monthly Recurring Revenue: ${total_mrr:.2f}\")\n        \n        return {\n            \"active\": len(active_subs),\n            \"cancelled\": len(cancelled_subs),\n            \"paused_subs\": len(paused_subs),\n            \"trialing_subs\": len(trialing_subs),\n            \"mrr\": total_mrr\n        }\n        \n    except Exception as e:\n        print(f\"\u274c Error managing subscriptions: {e}\")\n        return None\n\n# Cancel subscription with reason\ndef cancel_subscription_with_reason(client, subscription_id):\n    \"\"\"Cancel subscription with cancellation reason\"\"\"\n    try:\n        # Note: This assumes the SDK supports cancellation reasons\n        result = client.cancel_subscription(\n            subscription_id,\n        )\n        print(f\"\u2705 Subscription {subscription_id} cancelled\")\n        return result\n    except Exception as e:\n        print(f\"\u274c Failed to cancel subscription: {e}\")\n        return None\n\nmanage_subscriptions(client)\ncancel_subscription_with_reason(client, \"sub_1966676965965533186\")\n```\n\n\n## \ud83d\udca1 Example Code\n\nThe SDK includes comprehensive examples in the `examples/` directory:\n\n### Available Examples\n\n| File | Description | Use Case | Complexity |\n|------|-------------|----------|------------|\n| `basic_usage.py` | Basic SDK functionality | Getting started | Beginner |\n| `checkout_payments.py` | Complete payment flow | E-commerce integration | Intermediate |\n| `product_management.py` | Product CRUD operations | Catalog management | Intermediate |\n| `subscription_customer_management.py` | Subscription & customer ops | SaaS applications | Advanced |\n\n### Running Examples\n\n```bash\n# Set up environment\nexport BAGELPAY_API_KEY=\"your-test-api-key\"\nexport BAGELPAY_BASE_URL=\"https://test.bagelpay.io\"\n\n# Run basic example\npython examples/basic_usage.py\n\n# Run with verbose output\nBAGELPAY_DEBUG=true python examples/checkout_payments.py\n```\n\n\n## \u26a0\ufe0f Error Handling\n\n### Exception Hierarchy\n\n```python\nfrom bagelpay.exceptions import (\n    BagelPayError,              # Base exception class\n    BagelPayAPIError,           # API-related errors\n    BagelPayAuthenticationError, # Authentication failures\n    BagelPayValidationError,    # Request validation errors\n    BagelPayNotFoundError,      # Resource not found\n    BagelPayRateLimitError,     # Rate limiting\n    BagelPayNetworkError,       # Network connectivity issues\n    BagelPayTimeoutError        # Request timeout\n)\n\n# Exception hierarchy:\n# BagelPayError\n# \u251c\u2500\u2500 BagelPayAPIError\n# \u2502   \u251c\u2500\u2500 BagelPayAuthenticationError\n# \u2502   \u251c\u2500\u2500 BagelPayValidationError\n# \u2502   \u251c\u2500\u2500 BagelPayNotFoundError\n# \u2502   \u2514\u2500\u2500 BagelPayRateLimitError\n# \u251c\u2500\u2500 BagelPayNetworkError\n# \u2514\u2500\u2500 BagelPayTimeoutError\n```\n\n## \ud83e\uddea Testing Guide\n\n### Test Suite Overview\n\nThe SDK includes a comprehensive test suite with multiple testing strategies:\n\n```bash\n# Test runner with all options\npython run_tests.py --help\n\n# Basic test execution\npython run_tests.py                    # Run all tests\npython run_tests.py --unit             # Unit tests only\npython run_tests.py --integration      # Integration tests only\npython run_tests.py --mock             # Mock mode (no real API calls)\npython run_tests.py --coverage         # Generate coverage report\npython run_tests.py --fast             # Parallel execution\npython run_tests.py --verbose          # Detailed output\n```\n\n### Test Configuration\n\n```bash\n# Environment setup for testing\nexport BAGELPAY_API_KEY=\"test_key_12345\"\nexport BAGELPAY_BASE_URL=\"https://test.bagelpay.io\"\nexport BAGELPAY_TEST_MODE=\"true\"\nexport BAGELPAY_DEBUG=\"false\"\n\n# Install test dependencies\npip install pytest pytest-mock pytest-cov pytest-xdist responses\n\n# Or use the setup command\npython run_tests.py --setup\n```\n\n\n### Project Structure\n\n```\nbagelpay-sdk-python/\n\u251c\u2500\u2500 bagelpay/      # Main SDK package\n\u2502   \u251c\u2500\u2500 __init__.py         # Package initialization\n\u2502   \u251c\u2500\u2500 client.py           # Main client class\n\u2502   \u251c\u2500\u2500 models.py           # Data models\n\u2502   \u251c\u2500\u2500 exceptions.py       # Custom exceptions\n\u2502   \u2514\u2500\u2500 utils.py            # Utility functions\n\u251c\u2500\u2500 examples/               # Example scripts\n\u2502   \u251c\u2500\u2500 basic_usage.py      # Basic functionality\n\u2502   \u251c\u2500\u2500 checkout_payments.py # Payment processing\n\u2502   \u251c\u2500\u2500 product_management.py # Product operations\n\u2502   \u2514\u2500\u2500 subscription_customer_management.py # Advanced features\n\u251c\u2500\u2500 tests/                  # Test suite\n\u2502   \u251c\u2500\u2500 conftest.py         # Test configuration\n\u2502   \u251c\u2500\u2500 test_client.py      # Client tests\n\u2502   \u251c\u2500\u2500 test_models.py      # Model tests\n\u2502   \u251c\u2500\u2500 test_exceptions.py  # Exception tests\n\u2502   \u2514\u2500\u2500 test_integration.py # Integration tests\n\u251c\u2500\u2500 docs/                   # Documentation\n\u251c\u2500\u2500 requirements.txt        # Dependencies\n\u251c\u2500\u2500 setup.py               # Package setup\n\u251c\u2500\u2500 run_tests.py           # Test runner\n\u251c\u2500\u2500 pytest.ini            # Pytest configuration\n\u2514\u2500\u2500 README.md              # This file\n```\n\n### Contributing Guidelines\n\n1. **Fork and Clone**\n   ```bash\n   git fork https://github.com/bagelpay/bagelpay-sdk-python.git\n   git clone https://github.com/yourusername/bagelpay-sdk-python.git\n   ```\n\n2. **Create Feature Branch**\n   ```bash\n   git checkout -b feature/amazing-new-feature\n   ```\n\n3. **Make Changes**\n   - Follow existing code style\n   - Add tests for new functionality\n   - Update documentation\n   - Ensure all tests pass\n\n4. **Quality Checks**\n   ```bash\n   # Run all tests\n   python run_tests.py --coverage\n   \n   # Code quality\n   black bagelpay/\n   flake8 bagelpay/\n   mypy bagelpay/\n   ```\n\n5. **Commit and Push**\n   ```bash\n   git add .\n   git commit -m \"feat: add amazing new feature\"\n   git push origin feature/amazing-new-feature\n   ```\n\n6. **Create Pull Request**\n   - Provide clear description\n   - Include test results\n   - Reference related issues\n\n\n## \ud83d\ude80 Webhook Integration\n\n```python\nimport hmac\nimport hashlib\nimport json\n\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\nimport uvicorn\nfrom pyngrok import ngrok\nngrok.set_auth_token(\"your_ngrok_key\")\nWEBHOOK_SECRET = \"your_webhook_key\"\n\napp = FastAPI()\n\n\ndef verify_webhook_signature(signature_data: bytes, signature: str, secret: str) -> bool:\n    \"\"\"Verify webhook signature for security\"\"\"\n    expected_signature = hmac.new(\n        secret.encode('utf-8'),\n        signature_data,\n        hashlib.sha256\n    ).hexdigest()\n\n    return hmac.compare_digest(expected_signature, signature)\n\n\n@app.post(\"/api/webhooks\")\nasync def handle_post(request: Request):\n    \"\"\"Handle BagelPay webhook notifications\"\"\"\n    payload = await request.body()\n    timestamp = request.headers.get('timestamp').encode()\n    signature = request.headers.get('bagelpay_signature')\n    # Combine payload and timestamp\n    signature_data = timestamp + \".\".encode() + payload\n\n    if not verify_webhook_signature(signature_data, signature, WEBHOOK_SECRET):\n        return JSONResponse(status_code=401, content={\"error\": \"Invalid signature\"})\n\n    try:\n        event = json.loads(payload)\n        event_type = event.get('event_type')\n        data = event.get('object')\n\n        if event_type == 'checkout.completed':\n            # handle checkout completed events\n            print(event)\n        elif event_type == 'checkout.failed':\n            # handle checkout failed events\n            print(event)\n        elif event_type == 'checkout.cancel':\n            # handle checkout cancelled events\n            print(event)\n        elif event_type == 'subscription.trialing':\n            # handle subscription trialing events\n            print(event)\n        elif event_type == 'subscription.paid':\n            # handle subscription paid events\n            print(event)\n        elif event_type == 'subscription.canceled':\n            # handle subscription cancelled events\n            print(event)\n        elif event_type == 'refund.created':\n            # handle refund created events\n            print(event)\n        else:\n            print(f\"Unhandled event type: {event_type}\")\n\n        return JSONResponse(status_code=200, content={\"message\": \"Success\"})\n    except Exception as e:\n        print(f\"Webhook processing error: {e}\")\n        return JSONResponse(status_code=500, content={\"error\": \"Processing failed\"})\n\n\nif __name__ == \"__main__\":\n    listening_port = \"8000\"\n    public_url = ngrok.connect(\n        addr=listening_port,\n        proto=\"http\",\n        hostname=\"stunning-crane-direct.ngrok-free.app\"\n    )\n    print(f\"ngrok Public URL: {public_url}\")\n    uvicorn.run(app, host=\"0.0.0.0\", port=int(listening_port))\n```\n\n\n## \u2753 FAQ\n\n### General Questions\n\n**Q: What Python versions are supported?**\n\nA: The SDK supports Python 3.8+ with the following recommendations:\n- **Recommended**: Python 3.11 or higher\n- **Minimum**: Python 3.8\n- **Tested on**: Python 3.8, 3.9, 3.10, 3.11, 3.12\n\n**Q: How do I switch between test and production environments?**\n\n```python\n# Test environment\ntest_client = BagelPayClient(\n    base_url=\"https://test.bagelpay.io\",\n    api_key=\"test_key_xxx\"\n)\n\n# Production environment\nprod_client = BagelPayClient(\n    base_url=\"https://live.bagelpay.io\",\n    api_key=\"live_key_xxx\"\n)\n```\n\n**Q: How do I handle webhook verification?**\n\n```python\nimport hmac\nimport hashlib\n\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\nimport uvicorn\nfrom pyngrok import ngrok\nngrok.set_auth_token(\"your_ngrok_key\")\nWEBHOOK_SECRET = \"your_webhook_key\"\n\napp = FastAPI()\n\n\ndef verify_webhook_signature(signature_data: bytes, signature: str, secret: str) -> bool:\n    \"\"\"Verify webhook signature for security\"\"\"\n    expected_signature = hmac.new(\n        secret.encode('utf-8'),\n        signature_data,\n        hashlib.sha256\n    ).hexdigest()\n\n    print(\"expected_signature: \", expected_signature)\n    print(\"signature: \", signature)\n\n    return hmac.compare_digest(expected_signature, signature)\n\n\n@app.post(\"/api/webhooks\")\nasync def handle_post(request: Request):\n    \"\"\"Handle BagelPay webhook notifications\"\"\"\n    payload = await request.body()\n    timestamp = request.headers.get('timestamp').encode()\n    signature = request.headers.get('bagelpay_signature')\n    # Combine payload and timestamp\n    signature_data = timestamp + \".\".encode() + payload\n    print(\"payload: \", payload)\n    print(\"timestamp: \", timestamp)\n    print(\"signature: \", signature)\n    print(\"signature_data: \", signature_data)\n\n    if not verify_webhook_signature(signature_data, signature, WEBHOOK_SECRET):\n        return JSONResponse(status_code=401, content={\"error\": \"Invalid signature\"})\n\n    print(payload)\n    return JSONResponse(status_code=200, content={\"message\": \"Success\"})\n\n\nif __name__ == \"__main__\":\n    listening_port = \"8000\"\n    public_url = ngrok.connect(\n        addr=listening_port,\n        proto=\"http\",\n        hostname=\"stunning-crane-direct.ngrok-free.app\"\n    )\n    print(f\"ngrok Public URL: {public_url}\")\n    uvicorn.run(app, host=\"0.0.0.0\", port=int(listening_port))\n```\n\n\n### Integration Questions\n\n**Q: How do I integrate with popular web frameworks?**\n\n**Flask Integration:**\n```python\nfrom flask import Flask, request, jsonify\nfrom bagelpay import BagelPayClient\n\napp = Flask(__name__)\nclient = BagelPayClient(api_key=os.getenv('BAGELPAY_API_KEY'))\n\n@app.route('/create-payment', methods=['POST'])\ndef create_payment():\n    try:\n        data = request.get_json()\n        \n        checkout_request = CheckoutRequest(...)\n        response = client.create_checkout(checkout_request)\n        \n        return jsonify({\n            'success': True,\n            'payment_url': response.data.checkout_url,\n            'payment_id': response.data.payment_id\n        })\n        \n    except Exception as e:\n        return jsonify({\n            'success': False,\n            'error': str(e)\n        }), 400\n```\n\n**Django Integration:**\n```python\n# views.py\nfrom django.http import JsonResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.views.decorators.http import require_http_methods\nimport json\n\n@csrf_exempt\n@require_http_methods([\"POST\"])\ndef create_payment(request):\n    try:\n        data = json.loads(request.body)\n        \n        # Use your BagelPay client here\n        checkout_request = CheckoutRequest(...)\n        response = client.create_checkout(checkout_request)\n        \n        return JsonResponse({\n            'success': True,\n            'payment_url': response.data.checkout_url\n        })\n        \n    except Exception as e:\n        return JsonResponse({\n            'success': False,\n            'error': str(e)\n        }, status=400)\n```\n\n\n## \ud83d\udcde Support and Resources\n\n### Getting Help\n\n- \ud83d\udcd6 **Official Documentation**: [https://bagelpay.gitbook.io/docs](https://bagelpay.gitbook.io/docs)\n- \ud83d\udce7 **Technical Support**: support@bagelpayment.com\n- \ud83d\udc1b **Bug Reports**: [GitHub Issues](https://github.com/bagelpay/bagelpay-sdk-python/issues)\n\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## \ud83d\udd17 Related Links\n\n- [BagelPay Website](https://bagelpay.io)\n- [API Documentation](https://bagelpay.gitbook.io/docs/apireference)\n- [Developer Dashboard](https://bagelpay.io/dashboard)\n- [Privacy Policy](https://bagelpay.io/privacy)\n- [Terms of Service](https://bagelpay.io/terms)\n\n---\n\n**Start building with BagelPay SDK and make payment integration simple!** \ud83c\udf89\n\n*For the latest updates and announcements, follow us on [Twitter](https://x.com/BagelPay) and [LinkedIn](https://www.linkedin.com/company/bagel-payment).*\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "BagelPay Python SDK",
    "version": "1.0.1",
    "project_urls": {
        "Bug Reports": "https://github.com/bagelpay/bagelpay-sdk-python/issues",
        "Documentation": "https://bagelpay.gitbook.io/docs/documentation/sdks/python",
        "Homepage": "https://bagelpay.io",
        "Repository": "https://github.com/bagelpay/bagelpay-sdk-python"
    },
    "split_keywords": [
        "bagelpay",
        " payment",
        " api",
        " sdk",
        " python"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "41b299736684565e6a4b4996855c1e860c738366528cd3aa94b6f299b3ab6200",
                "md5": "d88556753b07f97d969593fe63f7d9d3",
                "sha256": "8bf85421138f41aef0853bf4a4a2f28805dddb14f73e1de03ac8eba8d8a8f523"
            },
            "downloads": -1,
            "filename": "bagelpay-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d88556753b07f97d969593fe63f7d9d3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 15576,
            "upload_time": "2025-09-15T01:15:22",
            "upload_time_iso_8601": "2025-09-15T01:15:22.979031Z",
            "url": "https://files.pythonhosted.org/packages/41/b2/99736684565e6a4b4996855c1e860c738366528cd3aa94b6f299b3ab6200/bagelpay-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6ca1bbe460aa002075f9e2d080a342a40c30168705e26e812b652554bcd667b2",
                "md5": "3ea9c46601fda15f4b1c463525e53e3b",
                "sha256": "c562d0ff144ae5d969d5173fd94ec835ec2e2e890b06d57543bdc6fb47bce8d5"
            },
            "downloads": -1,
            "filename": "bagelpay-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "3ea9c46601fda15f4b1c463525e53e3b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 32997,
            "upload_time": "2025-09-15T01:15:24",
            "upload_time_iso_8601": "2025-09-15T01:15:24.530011Z",
            "url": "https://files.pythonhosted.org/packages/6c/a1/bbe460aa002075f9e2d080a342a40c30168705e26e812b652554bcd667b2/bagelpay-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-15 01:15:24",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "bagelpay",
    "github_project": "bagelpay-sdk-python",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "requests",
            "specs": [
                [
                    ">=",
                    "2.25.0"
                ]
            ]
        },
        {
            "name": "typing-extensions",
            "specs": [
                [
                    ">=",
                    "4.0.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "pytest-cov",
            "specs": [
                [
                    ">=",
                    "4.0.0"
                ]
            ]
        },
        {
            "name": "pytest-mock",
            "specs": [
                [
                    ">=",
                    "3.10.0"
                ]
            ]
        },
        {
            "name": "coverage",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "black",
            "specs": [
                [
                    ">=",
                    "22.0.0"
                ]
            ]
        },
        {
            "name": "flake8",
            "specs": [
                [
                    ">=",
                    "5.0.0"
                ]
            ]
        },
        {
            "name": "mypy",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "twine",
            "specs": [
                [
                    ">=",
                    "4.0.0"
                ]
            ]
        },
        {
            "name": "wheel",
            "specs": [
                [
                    ">=",
                    "0.38.0"
                ]
            ]
        },
        {
            "name": "setuptools",
            "specs": [
                [
                    ">=",
                    "65.0.0"
                ]
            ]
        },
        {
            "name": "colorama",
            "specs": [
                [
                    ">=",
                    "0.4.6"
                ]
            ]
        },
        {
            "name": "tabulate",
            "specs": [
                [
                    ">=",
                    "0.9.0"
                ]
            ]
        }
    ],
    "lcname": "bagelpay"
}
        
Elapsed time: 1.61227s