Metadata-Version: 2.4
Name: pulseroute
Version: 0.1.0
Summary: PulseRoute SDK — predictive payment routing with automatic failover
Project-URL: Homepage, https://pulseroute.dev
Project-URL: Documentation, https://c9zealous.github.io/pulseroute-docs
Project-URL: Repository, https://github.com/c9zealous/pulseroute
Author-email: PulseRoute <hello@pulseroute.dev>
License-Expression: MIT
License-File: LICENSE
Keywords: failover,fintech,payments,pulseroute,routing
Classifier: Development Status :: 3 - Alpha
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# PulseRoute Python SDK

Zero-dependency Python client for [PulseRoute](https://pulseroute.dev) predictive payment routing. Uses only the standard library.

## Installation

```bash
pip install pulseroute
```

## Quick Start

```python
import os
from pulseroute import PulseRouteClient, RouteRequest, OutcomeRequest

client = PulseRouteClient(
    api_key=os.environ["PULSEROUTE_KEY"],
    base_url="https://api.pulseroute.dev",
)

# Pre-transaction: get routing decision
route = client.get_route(RouteRequest(country="US", currency="USD", card_type="visa"))

# Process payment with route.processor_id...

# Post-transaction: report outcome (fire-and-forget)
client.report_outcome(OutcomeRequest(
    rule_id=route.rule_id,
    processor_id=route.processor_id,
    success=True,
    latency_ms=145.0,
))

# On shutdown
client.shutdown()
```

## Stripe + Adyen Example

```python
import time

def process_payment(country, currency, card_type, amount_cents):
    route = client.get_route(RouteRequest(country=country, currency=currency, card_type=card_type))
    start = time.time()

    try:
        if route.processor_id == "stripe":
            result = stripe.Charge.create(amount=amount_cents, currency=currency)
        else:
            result = adyen.payments.create(amount=amount_cents, currency=currency)

        latency = (time.time() - start) * 1000
        client.report_outcome(OutcomeRequest(
            rule_id=route.rule_id,
            processor_id=route.processor_id,
            success=True,
            latency_ms=latency,
        ))
        return result

    except PaymentError as e:
        latency = (time.time() - start) * 1000
        client.report_outcome(OutcomeRequest(
            rule_id=route.rule_id,
            processor_id=route.processor_id,
            success=False,
            latency_ms=latency,
            error_code=e.code,
        ))
        raise
```

## Context Manager

```python
with PulseRouteClient(api_key="your-key") as client:
    route = client.get_route(RouteRequest(country="US", currency="USD"))
    # ... process payment ...
# Auto-flushes and shuts down on exit
```

## Configuration

| Option | Default | Description |
|--------|---------|-------------|
| `api_key` | `None` | API key for authentication |
| `base_url` | `http://localhost:8080` | PulseRoute API URL |
| `timeout` | 5.0 | HTTP request timeout (seconds) |
| `flush_interval` | 5.0 | Outcome flush interval (seconds) |
| `batch_size` | 50 | Max outcomes per flush |

## Features

- **Zero dependencies** — uses only Python standard library (`urllib`, `json`, `threading`)
- **Local decision cache** — falls back to cached decision if API unreachable
- **Fire-and-forget outcomes** — buffered and flushed async in batches
- **Thread-safe** — daemon flush thread, lock-protected buffer
- **Context manager** — works with `with` statements
