# InventPay Python SDK

![InventPay](https://img.shields.io/badge/InventPay-SDK-blue)
![Version](https://img.shields.io/pypi/v/inventpay)
![License](https://img.shields.io/pypi/l/inventpay)

The official Python SDK for [InventPay](https://inventpay.io) - Accept crypto payments, manage stores, handle withdrawals, and receive real-time notifications with ease.

## Features

- 💳 **Accept Crypto Payments** - Bitcoin, Ethereum, Litecoin, USDT (ERC20 & BEP20)
- 🏪 **Store Management** - Create storefronts, add digital products, manage orders
- 🔄 **Secure Withdrawals** - Withdraw funds with a dedicated withdrawal API key
- 💰 **Balance Tracking** - Real-time balance and limit monitoring
- 🔔 **Webhook Support** - Secure payment notifications and event handling
- 🎯 **Dual Payment Modes** - Fixed currency or multi-currency invoices
- 🐍 **Pythonic API** - Full type hints and dataclass support
- ⚡ **Lightweight** - Minimal dependencies (only `requests`)

## Installation

```bash
pip install inventpay
```

## Quick Start

```python
import os
from inventpay import PaymentSDK, SDKConfig

# Initialize with your API key
sdk = PaymentSDK(SDKConfig(
    api_key=os.getenv("INVENTPAY_API_KEY"),
    withdrawal_api_key=os.getenv("INVENTPAY_WITHDRAWAL_KEY"),  # Optional
))

# Test the connection
result = sdk.test_connection()
print(result["message"])  # "API connection successful"
```

## Accepting Payments

### Option 1: Fixed Currency Payment

```python
from inventpay import PaymentRequest

payment = sdk.create_payment(PaymentRequest(
    amount=29.99,
    currency="USDT_BEP20",
    order_id="order-12345",
    description="Premium Plan",
))

print(f"Payment ID: {payment.data['paymentId']}")
print(f"Address: {payment.data['address']}")
print(f"Invoice URL: {payment.data['invoiceUrl']}")
```

### Option 2: Multi-Currency Invoice

```python
from inventpay import InvoiceRequest

invoice = sdk.create_invoice(InvoiceRequest(
    amount=49.99,
    order_id="order-67890",
    description="E-commerce Purchase",
))

print(f"Invoice URL: {invoice.data['invoiceUrl']}")
```

### Check Payment Status

```python
status = sdk.get_payment_status("your-payment-id")
print(f"Status: {status.status}")  # PENDING, COMPLETED, EXPIRED, FAILED
```

## Managing Balances

```python
# Get all balances
balances = sdk.get_balances()
for currency, info in balances.data["balances"].items():
    print(f"{currency}: {info['availableBalance']} available")

# Get specific currency balance
usdt = sdk.get_balance("USDT_BEP20")
print(f"USDT: {usdt.data['balance']['availableBalance']}")
```

## Withdraw Funds

Programmatic withdrawals require a **Withdrawal API Key** — a separate key from your main API key, disabled by default for security.

1. Go to **Dashboard → Settings → Withdrawal API Key**
2. Click **"Generate Key"** to create your `wk_live_...` key
3. Pass it when initializing the SDK

```python
sdk = PaymentSDK(SDKConfig(
    api_key=os.getenv("INVENTPAY_API_KEY"),
    withdrawal_api_key=os.getenv("INVENTPAY_WITHDRAWAL_KEY"),
))

from inventpay import WithdrawalRequest

withdrawal = sdk.create_withdrawal(WithdrawalRequest(
    amount=10.0,
    currency="USDT_BEP20",
    destination_address="0x1E3D6848dE165e64052f0F2A3dA8823A27CAc22D",
    description="Monthly payout",
))

print(f"Withdrawal ID: {withdrawal.data['withdrawalId']}")
print(f"Status: {withdrawal.data['status']}")
```

> **Note:** If `withdrawal_api_key` is not provided, `create_withdrawal()` will raise a `PaymentSDKError`.

## Store Management

Create and manage digital storefronts with products and orders.

### Create a Store

```python
from inventpay import CreateStoreRequest

store = sdk.create_store(CreateStoreRequest(
    name="My Digital Shop",
    description="Premium digital products",
))

print(f"Store slug: {store.data['slug']}")
# Store URL: https://inventpay.io/store/{slug}
```

### Add Products

```python
from inventpay import CreateProductRequest

product = sdk.create_product(CreateProductRequest(
    name="Premium Template Pack",
    price=29.99,
    currency="USD",
    description="50+ professional templates",
    stock=100,
    digital_content={
        "fileUrl": "https://yourstorage.com/templates.zip",
        "instructions": "Download link valid for 24 hours",
    },
))
```

### List Products

```python
products = sdk.list_products(page=1, limit=20)
for p in products.data["products"]:
    print(f"{p['name']} - ${p['price']}")
```

### Manage Orders

```python
# List orders
orders = sdk.list_orders(status="PAID", limit=10)

# Get order details
order = sdk.get_order("order-id")

# Update fulfillment status
sdk.update_order_status("order-id", "COMPLETED")
```

### Update & Delete Products

```python
from inventpay import UpdateProductRequest

sdk.update_product("product-id", UpdateProductRequest(price=24.99, stock=50))
sdk.delete_product("product-id")
```

## Key Pool (Unique Keys Per Customer)

Upload unique keys/codes to a product. Each customer gets one unique key on purchase (FIFO).

```python
# Upload keys to a product's pool
result = sdk.add_product_keys("product-id", [
    "LICENSE-AAAA-0001",
    "LICENSE-AAAA-0002",
    "LICENSE-AAAA-0003",
], label="January Batch")
print(f"Added {result['data']['added']} keys")

# Check pool stats
stats = sdk.get_key_pool_stats("product-id")
print(f"{stats['data']['available']} keys available")

# List keys (with optional status filter)
keys = sdk.list_product_keys("product-id", status="AVAILABLE", limit=20)

# Remove all available (unassigned) keys
sdk.remove_available_keys("product-id")
```

> When a customer purchases the product, one key is automatically assigned and delivered alongside the product's digital content.

## Webhook Handling

### Configure Webhooks

```python
from inventpay import WebhookConfig

sdk.configure_webhook(WebhookConfig(
    webhook_url="https://yourapp.com/webhooks/inventpay"
))
```

### Flask Webhook Handler

```python
from flask import Flask, request, jsonify
from inventpay import verify_webhook_signature

app = Flask(__name__)
WEBHOOK_SECRET = "your-webhook-secret-from-dashboard"

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

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

    event_type = payload.get("event")
    if event_type == "payment.completed":
        print(f"Payment completed: {payload['data']['paymentId']}")

    return jsonify({"received": True})
```

## Error Handling

```python
from inventpay import PaymentSDKError, AuthenticationError, ValidationError

try:
    payment = sdk.create_payment(PaymentRequest(amount=25, currency="USDT_BEP20"))
except AuthenticationError as e:
    print(f"Invalid API key: {e.message}")
except ValidationError as e:
    print(f"Invalid request: {e.message} - {e.details}")
except PaymentSDKError as e:
    print(f"API error: {e.message} (Status: {e.status_code})")
```

## API Reference

### Payment Methods

| Method | Description |
|--------|-------------|
| `create_payment()` | Create fixed currency payment |
| `create_invoice()` | Create multi-currency invoice |
| `get_payment_status()` | Check payment status |

### Balance Methods

| Method | Description |
|--------|-------------|
| `get_balances()` | Get all currency balances |
| `get_balance(currency)` | Get specific currency balance |

### Withdrawal Methods

| Method | Description |
|--------|-------------|
| `create_withdrawal()` | Create withdrawal (requires key) |
| `get_withdrawal()` | Check withdrawal status |

### Store Methods

| Method | Description |
|--------|-------------|
| `create_store()` | Create a new store |
| `get_store()` | Get store details |
| `update_store()` | Update store settings |
| `create_product()` | Add a product |
| `list_products()` | List all products |
| `update_product()` | Update a product |
| `delete_product()` | Delete (deactivate) a product |
| `add_product_keys()` | Upload keys to product pool |
| `list_product_keys()` | List keys in pool |
| `get_key_pool_stats()` | Get pool stats |
| `remove_available_keys()` | Remove available keys |
| `list_orders()` | List store orders |
| `get_order()` | Get order details |
| `update_order_status()` | Update order status |

### Webhook Methods

| Method | Description |
|--------|-------------|
| `configure_webhook()` | Set webhook URL |
| `get_webhook_config()` | Get webhook configuration |
| `test_webhook()` | Test webhook endpoint |
| `get_webhook_deliveries()` | Get delivery history |
| `get_webhook_stats()` | Get delivery statistics |
| `delete_webhook()` | Remove webhook configuration |

## Configuration

```python
config = SDKConfig(
    api_key="your-api-key",                    # Required
    withdrawal_api_key="wk_live_...",          # Optional — for programmatic withdrawals
    base_url="https://api.inventpay.io",       # Optional
    timeout=30,                                # Optional (seconds)
)
```

### Supported Currencies

- `BTC` - Bitcoin
- `ETH` - Ethereum
- `LTC` - Litecoin
- `USDT_ERC20` - USDT on Ethereum
- `USDT_BEP20` - USDT on Binance Smart Chain

## Support

- **Documentation:** [https://docs.inventpay.io](https://docs.inventpay.io)
- **Dashboard:** [https://inventpay.io/dashboard](https://inventpay.io/dashboard)
- **Email Support:** support@inventpay.io

## License

MIT License - see [LICENSE](LICENSE) for details.
