Metadata-Version: 2.5
Name: simplr-ai
Version: 2.0.1
Summary: Simplr server-side SDK for Python — checks, profiles, RUM, AI delegation, feature flags, and webhook verification.
Project-URL: Homepage, https://simplr-ai.com
Project-URL: Documentation, https://simplr-docs-three.vercel.app/sdks/python
Project-URL: Repository, https://github.com/doshexchnage/simplr-sdk
Author: Simplr
License: Simplr Commercial SDK License
        
        Copyright (c) 2026 Simplr. All rights reserved.
        
        This software and its accompanying documentation are proprietary commercial
        software owned by Simplr.
        
        Use, copying, modification, and distribution are permitted only under a valid
        agreement with Simplr, including the Simplr Terms of Service available at
        https://simplr-ai.com/terms. No rights are granted except as expressly stated
        in that agreement.
        
        This software is not open-source software. You may not publish its source,
        redistribute it as a standalone product, sublicense it, sell it, or use it to
        create a competing product except where expressly permitted by your agreement
        with Simplr or applicable law.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, EXCEPT AS EXPRESSLY PROVIDED IN A WRITTEN AGREEMENT WITH SIMPLR.
License-File: LICENSE
Keywords: feature-flags,fraud,identity,server,simplr,webhooks
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
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: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Description-Content-Type: text/markdown

# simplr

Simplr's **server-side** SDK for Python — run fraud/identity checks, score orders, manage profiles, emit server-side RUM, create AI delegations, evaluate feature flags locally, and verify webhook signatures, all with your secret key.

> This is the backend SDK. For client-side device signals, RUM, and feature-flag evaluation use the browser/mobile SDKs.

Docs: https://simplr-docs-three.vercel.app/sdks/python

## Install

```bash
pip install simplr-ai
```

Requires Python 3.9+. **Zero runtime dependencies** — uses only the standard library (`urllib.request`, `hmac`, `hashlib`).

## Quick start

```python
import os
from simplr import Simplr

simplr = Simplr(api_key=os.environ["SIMPLR_API_KEY"])  # sk_live_… / sk_test_…

result = simplr.check({"email": "user@example.com", "event_type": "signup"})
if result["risk_level"] in ("high", "critical"):
    ...  # require extra verification
```

`base_url` defaults to `https://api.simplr-ai.com`; override it for local/dev:

```python
Simplr(api_key="sk_test_…", base_url="http://localhost:7002")
```

## Checks

```python
simplr.check({"phone": "+14155550100", "event_type": "login"})
simplr.check_bulk([{"email": "a@x.com"}, {"phone": "+1..."}])  # up to 100
```

## Orders

```python
simplr.orders.submit({
    "external_order_id": "o_1",
    "external_id": "cust_1",
    "amount_cents": 24900,
    "currency": "USD",
})
simplr.orders.submit_bulk([...])  # up to 100 orders
```

## Phone intelligence

```python
simplr.phone.report({"phone": "+14155550100", "outcome": "sim_swap_fraud", "confidence": 0.9})
simplr.phone.intelligence("+14155550100")
```

## Edge devices & logs

```python
simplr.edge.register_device({"device_id": "POS-0042", "name": "Front till"})
simplr.edge.heartbeat("POS-0042", {"cpu": 0.34, "battery": 0.78})
simplr.edge.ingest_logs("POS-0042", [{"category": "transaction", "level": "info", "message": "sale ok"}])
```

## Server-side feature flags

Evaluate flags on the backend. Flag config is read with a **public** key (`pk_…`), so pass one alongside your secret key; evaluation is local and deterministic (same bucketing as the browser SDK).

```python
simplr = Simplr(
    api_key=os.environ["SIMPLR_API_KEY"],       # sk_… for checks/orders/etc.
    public_key=os.environ["SIMPLR_PUBLIC_KEY"], # pk_… for flags
)

simplr.flags.initialize()
simplr.flags.set_user("user_123")

if simplr.flags.is_enabled("new-checkout"):
    ...  # gate a backend code path

simplr.flags.is_enabled("beta", user_id="u1", attributes={"plan": "growth"})
```

You can also use `SimplrFlags` standalone:

```python
from simplr import SimplrFlags

flags = SimplrFlags(public_key=os.environ["SIMPLR_PUBLIC_KEY"])
flags.initialize()
flags.is_enabled("new-checkout", user_id="user_123")
flags.dispose()  # stop the background refresh timer
```

The background refresh runs on a daemon timer, so it never keeps your process alive.

Named environments such as `dev`, `uat`, and `prod` are supported:

```python
simplr = Simplr(api_key=api_key, public_key=public_key, environment="uat")
```

## Profiles (`simplr.profiles`)

```python
simplr.profiles.identify("user-123", {
    "profile_type": "customer",
    "fingerprint_hash": "9f2a…",
})
simplr.profiles.submit_order({
    "external_order_id": "order-1",
    "external_id": "user-123",
    "amount_cents": 4999,
    "currency": "ZAR",
})
```

Profile reads and outcome reporting are portal-authorized management operations:

```python
from simplr import SimplrAdmin

admin = SimplrAdmin(token=os.environ["SIMPLR_PORTAL_TOKEN"])
risk = admin.profiles.get_profile_risk(org_id, "user-123")
admin.profiles.report_outcome(org_id, "user-123", "fraud")
```

## Server-side RUM (`simplr.rum`)

There is no browser auto-capture in a Python service. Report views, actions,
errors, and logs explicitly:

```python
simplr.rum.initialize("my-api", environment="production")
simplr.rum.set_user("user-123", {"plan": "pro"})
simplr.rum.track_view("POST /checkout")
simplr.rum.track_action("charge_card", {"gateway": "stripe"})

try:
    charge_card()
except Exception as error:
    simplr.rum.track_error(error)

simplr.rum.log("info", "checkout completed", {"order_id": "order-1"})
simplr.rum.flush()
simplr.rum.stop_session()
```

The flush timer is a daemon and does not keep the Python process alive.

## Network request logging

Enable shipping and add the zero-dependency middleware for your Python web
framework. FastAPI and Starlette use the ASGI middleware:

```python
from fastapi import FastAPI
from simplr import Simplr, SimplrASGIMiddleware

simplr = Simplr(
    api_key=os.environ["SIMPLR_API_KEY"],
    ship_network_logs=True,
    application_id="recommendation-ai",
    environment="prod",
)

app = FastAPI()
app.add_middleware(SimplrASGIMiddleware, client=simplr)
```

Flask and other WSGI applications can wrap the application:

```python
from simplr import SimplrWSGIMiddleware

app.wsgi_app = SimplrWSGIMiddleware(app.wsgi_app, simplr)
```

For jobs or custom clients, record a completed request explicitly:

```python
simplr.network.track(
    "POST",
    "https://recommendations.example/search/algolia",
    status=200,
    duration_ms=77.7,
)
simplr.flush_network_logs()
```

Or time a request with a context manager:

```python
with simplr.network.capture("POST", url) as request_log:
    response = httpx.post(url, json=payload)
    request_log.set_response(response.status_code)
```

`flush_network_logs()` returns `False` when Simplr rejects or only partially
processes a batch. Use `on_network_delivery_error` to send delivery failures to
your own logger. `log_self_calls=True` is separate and includes the SDK's calls
to Simplr itself; leave it disabled for normal application monitoring. Query
strings and fragments are omitted from captured URLs so credentials and personal
data are not sent through network telemetry. When body capture is enabled, JSON
keys are redacted and non-JSON textual bodies are omitted.

## AI delegation (`simplr.ai`)

```python
delegation = simplr.ai.create_delegation(
    "user-123",
    binding="verified_device",
    expires_in_days=7,
    fingerprint_hash="9f2a…",
)

validation = simplr.ai.validate(
    delegation["token"],
    ai_provider="openai",
    action="read_orders",
)
if not validation["valid"]:
    ...  # reject the request

simplr.ai.list("user-123")
simplr.ai.get(delegation["delegation_id"])
simplr.ai.stats()
simplr.ai.revoke(delegation["delegation_id"], "user revoked")
simplr.ai.revoke_all_for_user("user-123", "logout")
```

## Webhooks

Verify the `X-Simplr-Signature` header against the **raw** request body (don't re-serialize parsed JSON). Flask example:

```python
import os
from flask import Flask, request, abort
from simplr import Simplr, WebhookVerificationError

simplr = Simplr(api_key=os.environ["SIMPLR_API_KEY"])
app = Flask(__name__)

@app.post("/hooks/simplr")
def hook():
    sig = request.headers.get("X-Simplr-Signature", "")
    try:
        event = simplr.webhooks.construct_event(
            request.get_data(),  # raw bytes
            sig,
            os.environ["SIMPLR_WEBHOOK_SECRET"],
        )
    except WebhookVerificationError:
        abort(400)  # invalid signature
    # event["event"], event["data"]
    return "", 200
```

`verify(payload, header, secret, tolerance_sec=300)` returns a `bool`; `construct_event(...)` returns the parsed event or raises `WebhookVerificationError`. `tolerance_sec=0` disables the timestamp check. The module-level helpers are also exported as `verify_webhook` and `construct_webhook_event`.

## Admin / measurement (`SimplrAdmin`)

Dashboard operations — usage/measurement, feature-flag CRUD, and RUM analytics — require a **portal token** (JWT), not an API key:

```python
import os
from simplr import SimplrAdmin

admin = SimplrAdmin(token=os.environ["SIMPLR_PORTAL_TOKEN"])

admin.usage.stats(org_id)     # usage counters
admin.usage.billing(org_id)   # per-service totals + estimated cost
admin.flags.create(org_id, {"key": "new-checkout", "environment": "test", "rollout_percentage": 10})
admin.flags.update(org_id, flag_id, {"rollout_percentage": 50})
admin.rum.overview(org_id, application_id="my-app")
admin.rum.sessions(org_id, page=1, limit=50)
```

## Errors

Non-2xx responses raise `SimplrError` with `.status` and `.body`. Timeouts and network errors raise `SimplrError` with `.status == 0` and `.body is None`.

```python
from simplr import SimplrError

try:
    simplr.check({"email": "user@example.com"})
except SimplrError as err:
    print(err.status, err.message, err.body)
```

## Environment variables

By convention:

| Variable | Purpose |
| --- | --- |
| `SIMPLR_API_KEY` | Secret key (`sk_…`) for checks/orders/phone/edge |
| `SIMPLR_PUBLIC_KEY` | Public key (`pk_…`) for feature-flag reads |
| `SIMPLR_WEBHOOK_SECRET` | Webhook signing secret (`whsec_…`) |
| `SIMPLR_PORTAL_TOKEN` | Portal JWT for `SimplrAdmin` |

## Development

```bash
make dev    # editable install with pytest
make test   # python -m pytest
make build  # build sdist + wheel
```

## Release

PyPI releases are built and published by GitHub Actions from a
`python-v<version>` tag. The tag, `pyproject.toml`, and `simplr.__version__`
must match. PyPI Trusted Publishing must be configured for project `simplr-ai`,
repository `doshexchnage/simplr-sdk`, workflow `publish-python.yml`, and
environment `pypi`.

## License

Commercial software — see [LICENSE](LICENSE).
