Metadata-Version: 2.4
Name: kalir-python
Version: 0.1.0
Summary: Official Python SDK for the Kalir Public API — digital risk intelligence and signed webhooks.
License-Expression: MIT
Requires-Dist: httpx>=0.23.1,<0.29.0
Requires-Dist: attrs>=22.2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# kalir-python

Official Python SDK for the [Kalir](https://kalir.io) Public API: your organization's digital-risk intelligence (incidents, credential and infostealer exposure, phishing impersonation, dark-web and Telegram mentions) plus signed webhooks. Typed with `attrs`, built on `httpx`, sync and async.

```bash
pip install kalir-python
```

## Quickstart

Create an API key at **app.kalir.io → Developers → API Keys**.

```python
from kalir import AuthenticatedClient
from kalir.api.overview import get_overview
from kalir.api.phishing import list_phishing
from kalir.api.incidents import list_incidents
from kalir.models import ListIncidentsBucket, ListPhishingVerdict

client = AuthenticatedClient(base_url="https://api.kalir.io", token="klr_…")

with client as c:
    overview = get_overview.sync(client=c)
    print(overview.risk_score, overview.incidents.open_critical)

    phishing = list_phishing.sync(client=c, verdict=ListPhishingVerdict.CONFIRMED)
    for d in phishing.data:
        print(d.domain, "impersonates", d.impersonates)

    incidents = list_incidents.sync(client=c, bucket=ListIncidentsBucket.OPEN, limit=20)
```

Every endpoint has four functions: `sync`, `sync_detailed` (status + headers), `asyncio` and `asyncio_detailed`.

```python
async with AuthenticatedClient(base_url="https://api.kalir.io", token="klr_…") as c:
    overview = await get_overview.asyncio(client=c)
```

## Errors

Error responses share one envelope: `{"error": {"type", "message", "status", "retry_after"}}`. Use the `*_detailed` functions to inspect `status_code`, or pass `raise_on_unexpected_status=True` to the client.

## Webhooks

```python
from kalir.webhooks import construct_event, WebhookSignatureError

@app.post("/kalir-webhooks")  # Flask
def kalir_webhooks():
    try:
        event = construct_event(
            request.get_data(),                     # raw body
            request.headers.get("X-Kalir-Signature"),
            KALIR_WEBHOOK_SECRET,                   # whsec_…
        )
    except WebhookSignatureError:
        return "", 400
    if event["type"] == "incident.created":
        ...
    return "", 200
```

Respond `2xx` within 15 seconds. Failed deliveries are retried with exponential backoff for ~20 hours; deduplicate on the `X-Kalir-Event-Id` header.

Full reference: <https://app.kalir.io/developers/docs>
