Metadata-Version: 2.4
Name: keverd
Version: 2.0.1
Summary: Server-side Python SDK for Keverd — verify events and handle webhooks
Project-URL: Homepage, https://keverd.com
Project-URL: Repository, https://github.com/keverdai/keverd_py_sdk
Project-URL: Documentation, https://github.com/keverdai/keverd_py_sdk#readme
Author: Keverd
License-Expression: MIT
License-File: LICENSE
Keywords: device-fingerprinting,fraud-detection,keverd,risk-assessment,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: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# keverd

Server-side Python SDK for [Keverd](https://keverd.com). Verify browser/mobile `event_id`s and handle signed webhooks.

**Python 3.9+** · zero runtime dependencies · works with Flask, FastAPI, Django, and any Python backend.

## Install

```bash
pip install keverd
```

## Quick start

```python
import os
from keverd import Keverd

keverd = Keverd(secret_key=os.environ["KEVERD_SECRET_KEY"])  # kv_sk_live_… or kv_sk_test_…

# event_id comes from the browser/mobile SDK after fingerprinting
result = keverd.verify(event_id)

if result.get("action") == "block":
    # reject the request
    ...
elif result.get("action") == "allow":
    # continue
    ...
```

`verify()` maps to `POST /v2/verify` and is the **only** billable decision read. Keep secret keys on the server.

## FastAPI example

```python
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from keverd import Keverd

app = FastAPI()
keverd = Keverd(secret_key=os.environ["KEVERD_SECRET_KEY"])


class LoginBody(BaseModel):
    event_id: str
    email: str
    password: str


@app.post("/login")
def login(body: LoginBody):
    risk = keverd.verify(body.event_id)
    if risk.get("action") == "block":
        raise HTTPException(status_code=403, detail={"error": "Blocked", "reasons": risk.get("reasons")})
    # …authenticate user…
    return {"ok": True, "visitor_id": risk.get("visitor_id")}
```

## Webhooks (optional)

Sync `verify()` is enough for most flows. Configure a webhook in the dashboard when you want push delivery.

```python
import os
from fastapi import FastAPI, Request, Response
from keverd import Keverd

app = FastAPI()
keverd = Keverd(secret_key=os.environ["KEVERD_SECRET_KEY"])


@app.post("/webhooks/keverd")
async def keverd_webhook(request: Request):
    raw = await request.body()  # raw bytes — do not parse first
    event = keverd.webhooks.construct_event(
        raw,
        request.headers.get("x-keverd-signature", ""),
        os.environ["KEVERD_WEBHOOK_SECRET"],  # whsec_…
    )
    if event["type"] == "verification.completed":
        verification = event["data"]["object"]
        # same shape as verify()
    return Response(status_code=200)
```

## API

| Method | Description |
|--------|-------------|
| `Keverd(secret_key, base_url=…, timeout=…)` | Create a client |
| `keverd.verify(event_id)` | Billable verify → risk decision + signals |
| `keverd.webhooks.construct_event(payload, signature, secret)` | Verify inbound webhook signature |

## Errors

- `KeverdError` — validation / network / timeout
- `KeverdAPIError` — non-2xx from the API (`status_code`, `body`)
- `KeverdSignatureError` — bad webhook signature

## License

MIT
