Metadata-Version: 2.4
Name: arcticbison-rudis
Version: 0.1.0
Summary: Official Python SDK for Rudis — open-source crypto invoice and billing notifier
Project-URL: Homepage, https://github.com/Arcticbison-Dev/Rudis
Project-URL: Repository, https://github.com/Arcticbison-Dev/Rudis
Project-URL: Documentation, https://github.com/Arcticbison-Dev/Rudis
Author: Arctic Bison LLC
License: MIT
License-File: LICENSE
Keywords: billing,bitcoin,crypto,invoice,lightning,monero,payments,privacy,webhook
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.9
Requires-Dist: httpx>=0.25.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Description-Content-Type: text/markdown

# arcticbison-rudis

Official Python SDK for [Rudis](https://github.com/Arcticbison-Dev/Rudis) — the open-source crypto invoice and billing notifier supporting Lightning Network, Bitcoin on-chain, and Monero.

## Installation

```bash
pip install arcticbison-rudis
```

## Quick start

```python
import os
from rudis import RudisClient

client = RudisClient(
    base_url='https://your-rudis-instance.example.com',
    api_key=os.environ['RUDIS_API_KEY'],
)

# Create a Lightning invoice
invoice = client.invoices.create(
    customer_id='user-42',
    amount_sats=21000,
    rail='LN',
    metadata={'plan_id': 'operator', 'billing_period': 'monthly'},
)
print(invoice.bolt11)  # lnbc...

# Poll until paid or expired
settled = client.invoices.poll(invoice.id)
if settled.status == 'paid':
    print('Payment confirmed:', settled.paid_at)
```

## Invoices

```python
# Create — Lightning
invoice = client.invoices.create(customer_id='user-42', amount_sats=21000, rail='LN')
# Create — Bitcoin on-chain
invoice = client.invoices.create(customer_id='user-42', amount_sats=21000, rail='BTC')
# Create — Monero
invoice = client.invoices.create(customer_id='user-42', amount_sats=21000, rail='XMR')

# Get
invoice = client.invoices.get('inv_...')

# List (optionally filter by customer)
all_invoices = client.invoices.list()
user_invoices = client.invoices.list(customer_id='user-42')

# Poll until settled (polls every 3s, up to 100 attempts by default)
settled = client.invoices.poll('inv_...', interval=3.0, max_attempts=100)
```

## Subscriptions

```python
# Register subscription (call after first payment to enable auto-renewal)
sub = client.subscriptions.create(
    customer_id='user-42',
    plan_id='altostratus-operator',
    billing_period='monthly',
    rail='LN',
    webhook_url='https://your-app.example.com/webhooks/rudis',
    webhook_secret=os.environ['WEBHOOK_SECRET'],
)

# Get
sub = client.subscriptions.get('sub_...')

# List
all_subs = client.subscriptions.list()

# Cancel
sub = client.subscriptions.cancel('sub_...')
```

## Webhook verification

```python
# Flask example
from flask import Flask, request, abort
from rudis.webhook import verify_signature, parse_event

app = Flask(__name__)

@app.route('/webhooks/rudis', methods=['POST'])
def rudis_hook():
    sig = request.headers.get('X-Rudis-Signature', '')
    body = request.get_data()

    if not verify_signature(body, sig, os.environ['WEBHOOK_SECRET']):
        abort(401)

    event = parse_event(body)

    if event.type == 'invoice.paid':
        # activate subscription
        pass
    elif event.type == 'subscription.suspended':
        # revoke access
        pass

    return '', 200
```

```python
# FastAPI example
from fastapi import FastAPI, Request, HTTPException
from rudis.webhook import verify_signature, parse_event

app = FastAPI()

@app.post('/webhooks/rudis')
async def rudis_hook(request: Request):
    body = await request.body()
    sig  = request.headers.get('x-rudis-signature', '')

    if not verify_signature(body, sig, os.environ['WEBHOOK_SECRET']):
        raise HTTPException(status_code=401)

    event = parse_event(body)
    # dispatch on event.type...
    return {'ok': True}
```

## Async client

```python
import asyncio
from rudis import AsyncRudisClient

async def main():
    async with AsyncRudisClient(
        base_url='https://your-rudis-instance.example.com',
        api_key=os.environ['RUDIS_API_KEY'],
    ) as client:
        invoice = await client.invoices.create(
            customer_id='user-42',
            amount_sats=21000,
            rail='LN',
        )
        settled = await client.invoices.poll(invoice.id)
        print(settled.status)

asyncio.run(main())
```

## Context manager

```python
with RudisClient(base_url=..., api_key=...) as client:
    invoices = client.invoices.list('user-42')
```

## Error handling

```python
from rudis import RudisError

try:
    invoice = client.invoices.get('inv_nonexistent')
except RudisError as e:
    print(e.status_code)  # 404
    print(e.body)         # {"message": "Invoice not found"}
```

## Self-hosted Rudis

Point `base_url` at your self-hosted instance:

```python
client = RudisClient(base_url='http://localhost:3000', api_key=os.environ['INVOICE_API_KEY'])
```

## Requirements

- Python 3.9+
- [httpx](https://www.python-httpx.org/) (installed automatically)

## License

MIT — same as Rudis itself.
