> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raxe.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Complete Python SDK reference

## Installation

```bash theme={null}
pip install raxe
```

## Basic Usage

```python title="basic.py" theme={null}
from raxe import Raxe

# Initialize RAXE client
raxe = Raxe()

# Scan a prompt
result = raxe.scan("Ignore all previous instructions")

# Check for threats
if result.has_threats:
    print(f"Threat detected!")
    print(f"Severity: {result.severity}")        # "critical", "high", "medium", "low"
    print(f"Total detections: {result.total_detections}")
```

## ScanPipelineResult Object

The `scan()` method returns a `ScanPipelineResult`:

```python title="result_example.py" theme={null}
result = raxe.scan("test prompt")

# Boolean evaluation - True when SAFE
if result:  # True when no threats
    print("Safe to proceed")
else:
    print("Threat detected")

# Properties
result.has_threats        # bool: True if any threat detected
result.severity           # str | None: "critical", "high", "medium", "low", "info"
result.total_detections   # int: Number of detections (L1 + L2)
result.detections         # list[Detection]: All L1 detections
result.duration_ms        # float: Total scan time in milliseconds
result.should_block       # bool: True if policy says to block
result.l1_detections      # int: Count of L1 detections
result.l2_detections      # int: Count of L2 predictions
result.text_hash          # str: SHA256 hash of scanned text (for logging)
```

## Detection Object

Each detection contains:

```python title="detection_example.py" theme={null}
for detection in result.detections:
    detection.rule_id      # str: "pi-001" - unique rule identifier
    detection.rule_version # str: "1.0.0" - rule version
    detection.severity     # Severity: Severity.HIGH - enum value
    detection.confidence   # float: 0.95 - detection confidence (0.0-1.0)
    detection.category     # str: "PI" - threat family code
    detection.matches      # list[Match]: Matched text spans
```

## Match Object

```python title="match_example.py" theme={null}
for detection in result.detections:
    for match in detection.matches:
        match.matched_text   # str: The matched content (for debugging only)
        match.start          # int: Start position in original text
        match.end            # int: End position in original text
```

## Configuration Options

```python title="config.py" theme={null}
from raxe import Raxe

raxe = Raxe(
    # API key (optional - reads from config or RAXE_API_KEY env var if not provided)
    api_key="raxe_...",

    # Telemetry (privacy-preserving - never transmits prompts)
    telemetry=True,        # Enable telemetry for threat intelligence

    # Detection layers
    l2_enabled=True,       # Enable ML detection (neural classifier)

    # L2 voting preset for threshold tuning
    voting_preset="balanced",  # "balanced" | "high_security" | "low_fp"
)
```

## Background Scanning

For latency-sensitive applications (FastAPI, real-time APIs), use background scan mode. The scan runs asynchronously on a worker thread -- your code continues immediately with \~0ms overhead.

```python title="background_mode.py" theme={null}
from raxe import Raxe
from raxe.sdk.agent_scanner import AgentScannerConfig, create_agent_scanner

raxe = Raxe()
scanner = create_agent_scanner(
    raxe,
    AgentScannerConfig(
        on_threat="log",
        execution_mode="background",
        on_threat_callback=lambda r: print(
            f"Threat: severity={r.severity}, hash={r.prompt_hash}"
        ),
    ),
)

# Returns in <1ms — scan runs in background
scanner.scan_prompt("user input")

# Your code continues immediately
result = call_llm(prompt)
```

### Execution Modes

| Mode               | Overhead  | Threat Result | Use Case                                    |
| ------------------ | --------- | ------------- | ------------------------------------------- |
| `"sync"` (default) | \~5-200ms | Inline        | When you need to block on threats           |
| `"background"`     | \~0ms     | Via callback  | Log-only monitoring, latency-sensitive apps |

<Note>
  Background mode is incompatible with `on_threat="block"`. If both are set, RAXE auto-corrects to sync mode with a warning.
</Note>

## Decorator Pattern

Protect functions automatically:

```python title="decorated.py" theme={null}
from raxe import Raxe, RaxeBlockedError

raxe = Raxe()

@raxe.protect
def generate_response(prompt: str) -> str:
    """Scanned before execution."""
    return llm.generate(prompt)

# Usage
try:
    response = generate_response(user_input)
except RaxeBlockedError as e:
    print(f"Blocked: {e.severity}")
    print(f"Rule: {e.rule_id}")
```

## Custom Threat Handling

```python title="custom_handling.py" theme={null}
from raxe import Raxe, RaxeException

raxe = Raxe()

def process_with_custom_logic(user_input: str) -> str:
    try:
        result = raxe.scan(user_input)
    except RaxeException as e:
        # Handle scan errors - decide fail open or fail closed
        logger.error(f"RAXE scan error: {e}")
        return generate_normally(user_input)  # Fail open example

    if result.has_threats:
        severity = result.severity

        if severity == "critical":
            # Block and alert security team
            alert_security_team(result)
            return "Request blocked."

        elif severity == "high":
            # Log and proceed with additional guardrails
            log_suspicious_activity(result)
            return generate_with_guardrails(user_input)

        else:
            # Low/Medium - log but allow
            log_detection(result)

    return generate_normally(user_input)
```

## Context Manager

Ensures proper cleanup:

```python title="context.py" theme={null}
from raxe import Raxe

# Automatic cleanup - recommended for scripts and short-lived processes
with Raxe() as raxe:
    result = raxe.scan("test prompt")
    # Process result...
# Telemetry automatically flushed on exit
```

## Error Handling

```python title="error_handling.py" theme={null}
from raxe import Raxe, RaxeBlockedError, RaxeException

raxe = Raxe()

try:
    result = raxe.scan(user_input, block_on_threat=True)
except RaxeBlockedError as e:
    # Threat was detected and blocked by policy
    print(f"Blocked: {e.result.severity}")
    print(f"Detections: {e.result.total_detections}")
    print(f"Rule: {e.rule_id}")
except RaxeException as e:
    # Other RAXE errors (config, initialization, etc.)
    print(f"Error: {e}")
    # Decide: fail open (allow) or fail closed (block)
```

## Filtering Detections

```python title="filtering.py" theme={null}
from raxe import Severity

result = raxe.scan(user_input)

# Filter by category (threat family)
pi_threats = [d for d in result.detections if d.category == "PI"]  # Prompt Injection
de_threats = [d for d in result.detections if d.category == "DE"]  # Data Exfiltration

# Filter by severity (using enum for type safety)
critical = [d for d in result.detections if d.severity == Severity.CRITICAL]
high_and_above = [d for d in result.detections if d.severity >= Severity.HIGH]

# Filter by confidence threshold
high_confidence = [d for d in result.detections if d.confidence >= 0.9]
```

## Multi-Tenant Scanning

For multi-customer deployments, pass `tenant_id` and `app_id` to resolve tenant-specific policies:

```python title="multi_tenant.py" theme={null}
from raxe import Raxe

raxe = Raxe()

# Scan with tenant context for policy resolution
result = raxe.scan(
    "Ignore all previous instructions",
    tenant_id="acme",      # Customer tenant identifier
    app_id="chatbot",      # Application within tenant
)

# Policy attribution for billing/audit
print(f"Policy: {result.metadata['effective_policy_id']}")
print(f"Mode: {result.metadata['effective_policy_mode']}")
print(f"Source: {result.metadata['resolution_source']}")
```

### Override Policy Per-Request

```python title="policy_override.py" theme={null}
# Override the tenant/app default policy for specific requests
result = raxe.scan(
    prompt,
    tenant_id="acme",
    app_id="chatbot",
    policy_id="strict"  # Force strict mode for this request
)
```

See [Multi-Tenant Policies](/concepts/multi-tenant) for full documentation.

## Thread Safety

The `Raxe` client is thread-safe:

```python title="threaded.py" theme={null}
from concurrent.futures import ThreadPoolExecutor
from raxe import Raxe

raxe = Raxe()  # Single instance - reuse across threads

def scan_prompt(prompt: str):
    return raxe.scan(prompt)

# Safe to use from multiple threads
with ThreadPoolExecutor(max_workers=10) as executor:
    results = list(executor.map(scan_prompt, prompts))
```

## What's Next

<CardGroup cols={2}>
  <Card title="Async SDK" icon="bolt" href="/sdk/async">
    High-throughput scanning with async support
  </Card>

  <Card title="Agentic Scanning" icon="robot" href="/sdk/agentic-scanning">
    Specialised scanning for AI agent workflows
  </Card>
</CardGroup>
