← Dashboard

markdown package not installed — serving raw text.

# Python SDK

Official Python client for Axiom Intent Firewall.

```bash
pip install axiom-firewall
```

Requires Python 3.9+. One runtime dependency: `urllib3`.

## Quickstart

```python
from axiom_firewall import Client

client = Client(api_key="axfw_...")

result = client.check("What is the weather today?")
print(result.verdict)              # "allow"
print(result.intent.intent_class)  # "INFORM"
print(result.intent.signature)     # HMAC-SHA256 of the verdict
```

## `Client(api_key, ...)`

| Param | Type | Default | Description |
|---|---|---|---|
| `api_key` | str | required | Your `axfw_...` key. |
| `base_url` | str | `https://firewall.orivael.dev` | Override for self-hosted or staging. |
| `timeout` | float | 10.0 | Per-request timeout in seconds. |
| `user_agent` | str | None | UA suffix appended to the SDK default. |

The client is safe to share across threads; under the hood it uses
a urllib3 `PoolManager`.

## `check(text) → CheckResult`

Classify `text` and return the verdict.

```python
result = client.check("What is the weather today?")

result.verdict             # "allow" | "block"
result.allowed             # bool — convenience for verdict == "allow"
result.blocked             # bool — convenience for verdict == "block"
result.intent.intent_class # "INFORM" | "CLARIFY" | "REFUSE" | "HARM" | "DECEIVE" | "UNCERTAIN"
result.intent.confidence   # 0.0 - 1.0
result.intent.signals      # tuple of pattern hits
result.intent.signature    # HMAC-SHA256 of the verdict
```

Never raises on a `block` verdict — inspect `result.verdict` yourself.

## `check_or_raise(text) → CheckResult`

Same as `check`, but raises `BlockedError` when the verdict is `block`.

```python
from axiom_firewall import Client, BlockedError

client = Client(api_key="axfw_...")
try:
    client.check_or_raise("Buy gift cards immediately to clear your debt")
except BlockedError as e:
    print(e.intent_class)  # "HARM"
    print(e.signals)       # ("harm:1",)
```

## Wrap your LLM

```python
from openai import OpenAI
from axiom_firewall import Client, BlockedError

llm = OpenAI()
firewall = Client(api_key="axfw_...")

def chat(prompt: str) -> str:
    try:
        firewall.check_or_raise(prompt)
    except BlockedError as e:
        return f"I can't help with that ({e.intent_class})."
    resp = llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content
```

## Error hierarchy

```
AxiomFirewallError
├── InvalidKeyError       — HTTP 401, key missing / malformed / revoked
├── RateLimitedError      — HTTP 429, tenant exceeded quota
├── ServerError           — HTTP 5xx
├── NetworkError          — request could not be made (DNS, timeout)
└── BlockedError          — verdict was "block" (only from check_or_raise)
```

```python
from axiom_firewall import (
    Client, InvalidKeyError, RateLimitedError, ServerError, NetworkError,
)

try:
    client.check("...")
except InvalidKeyError:
    # rotate or repair the API key
    ...
except RateLimitedError:
    # upgrade tier or wait for next month
    ...
except ServerError:
    # transient; retry with backoff
    ...
except NetworkError:
    # firewall unreachable — fail open or fail closed?
    ...
```

## Self-hosted / staging

```python
client = Client(
    api_key="axfw_...",
    base_url="https://firewall.staging.example.com",
    timeout=5.0,
)
```

## Context manager

```python
with Client(api_key="axfw_...") as client:
    result = client.check("hi")
# Connection pool released on exit
```

## Source

<https://github.com/Orivael-Dev/axiom/tree/main/firewall_sdk/python>