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

# SDK API

> Complete reference for every public function, class, and method in the ProofRail SDK

# SDK API

This is the canonical reference for the Python SDK. For tutorial-style introductions see [Quickstart](/quickstart); for framework-specific patterns see the [Framework adapters](/frameworks/langgraph).

## `proofrail.init()`

Configure the SDK. Call once at application startup before opening any chains.

```python theme={null}
proofrail.init(
    api_key: str,
    *,
    environment: str = "production",
    backend_url: str = "https://api.proofrail.dev",
    backend_timeout_seconds: float = 5.0,
    fail_modes: dict[str, str] | None = None,
    fail_mode: str | None = None,
    financial_approval_threshold_usd: float = 5000.0,
    cumulative_financial_threshold_usd: float = 10000.0,
    external_domains_allowlist: list[str] | None = None,
    high_risk_agents: list[str] | None = None,
    default_approval_timeout_hours: float = 24,
    fallback_approvers: list[str] | None = None,
    sensitive_field_patterns: list[str] | None = None,
    sensitive_value_patterns: list[str] | None = None,
    max_payload_string_length: int = 1000,
    enable_local_fast_path: bool = True,
    offline_buffer_max_events: int = 100,
)
```

**Required**

| Parameter | Type  | Description                                                     |
| --------- | ----- | --------------------------------------------------------------- |
| `api_key` | `str` | Your ProofRail API key, prefixed `prail_`. Treated as a secret. |

**Common**

| Parameter                 | Type    | Default                       | Description                                                                                                                  |
| ------------------------- | ------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `environment`             | `str`   | `"production"`                | Tag attached to every chain. Common values: `"production"`, `"staging"`, `"development"`.                                    |
| `backend_url`             | `str`   | `"https://api.proofrail.dev"` | Override for self-hosted or testing deployments.                                                                             |
| `backend_timeout_seconds` | `float` | `5.0`                         | Per-request timeout when calling the backend. Should be raised for high-latency networks (e.g., 15s for Supabase free-tier). |

**Failure handling**

| Parameter                   | Type             | Default                                       | Description                                                                                                                                                                                                                        |
| --------------------------- | ---------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fail_modes`                | `dict[str, str]` | See [Configuration](/reference/configuration) | Per-action-class behavior when the backend is unreachable. Keys are action categories (`financial`, `external_communication`, etc.); values are `"deny"` or `"allow"`. A `default` key sets the fallback for unmatched categories. |
| `fail_mode`                 | `str`            | None                                          | Legacy single-string parameter. Treated as `{"default": fail_mode}`. Don't pass both `fail_modes` and `fail_mode`.                                                                                                                 |
| `offline_buffer_max_events` | `int`            | `100`                                         | Number of events buffered locally if the backend is unreachable. Oldest events drop when the buffer fills.                                                                                                                         |

**Policy thresholds**

| Parameter                            | Type        | Default   | Description                                                                                          |
| ------------------------------------ | ----------- | --------- | ---------------------------------------------------------------------------------------------------- |
| `financial_approval_threshold_usd`   | `float`     | `5000.0`  | Single transactions above this require approval.                                                     |
| `cumulative_financial_threshold_usd` | `float`     | `10000.0` | Chain cumulative financial exposure above this requires approval on the next financial action.       |
| `external_domains_allowlist`         | `list[str]` | None      | Domains agents may communicate with without triggering exfiltration alerts.                          |
| `high_risk_agents`                   | `list[str]` | None      | Agent names treated as high-risk; every action by these agents requires approval.                    |
| `default_approval_timeout_hours`     | `float`     | `24`      | How long approval requests stay valid before timing out.                                             |
| `fallback_approvers`                 | `list[str]` | None      | Email addresses that receive escalations if primary approvers don't respond within half the timeout. |

**Privacy**

| Parameter                   | Type        | Default                                             | Description                                                                                                                |
| --------------------------- | ----------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `sensitive_field_patterns`  | `list[str]` | See [Sanitization defaults](#sanitization-defaults) | Field-name substrings that get redacted in payloads sent to the backend. Match is case-insensitive substring against keys. |
| `sensitive_value_patterns`  | `list[str]` | See [Sanitization defaults](#sanitization-defaults) | Value prefixes that get redacted. Match uses `str.startswith()` against string values.                                     |
| `max_payload_string_length` | `int`       | `1000`                                              | Strings longer than this are truncated before being sent.                                                                  |

**Performance**

| Parameter                | Type   | Default | Description                                                                                                                                           |
| ------------------------ | ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enable_local_fast_path` | `bool` | `True`  | Allow obviously-safe actions to be decided locally without a backend round-trip. Disable for strictest governance (every action goes to the backend). |

### Returns

A `ChainConfig` instance. Configuration is also stored globally for the process so subsequent `proofrail.Chain(...)` calls use it.

### Sanitization defaults

The SDK uses two separate default lists for redacting sensitive data:

`sensitive_field_patterns` (default — matches against dict keys by case-insensitive substring):

```
["api_key", "password", "secret", "token", "credit_card", "ssn", "private_key"]
```

`sensitive_value_patterns` (default — matches against string values using `str.startswith()`):

```
["sk_", "pk_", "ghp_", "hf_", "eyJ", "AKIA", "prail_"]
```

Custom patterns you pass via the corresponding kwarg are appended to the defaults.

***

## `proofrail.Chain`

Context manager that opens a chain and records every action within it. Use as an async or sync context manager depending on your code.

```python theme={null}
class Chain:
    def __init__(
        self,
        name: str,
        *,
        external_chain_id: str | None = None,
        metadata: dict | None = None,
    ): ...

    async def __aenter__(self) -> "Chain": ...
    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: ...

    def __enter__(self) -> "Chain": ...
    def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...

    async def record_agent_action(...) -> PolicyDecision: ...
```

### Constructor parameters

| Parameter           | Type   | Description                                                                                                                                                    |
| ------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | `str`  | Human-readable identifier shown in the dashboard. Conventional: hyphen-separated lowercase (`"vendor-purchase"`, `"customer-onboarding"`).                     |
| `external_chain_id` | `str`  | Your own ID for the chain, useful for cross-referencing with your internal systems. Stored unchanged.                                                          |
| `metadata`          | `dict` | Arbitrary JSON-serializable key/value pairs. Attached to the chain and visible in receipts. Stored as opaque data — the SDK does not interpret keys within it. |

### Lifecycle

On `__aenter__` / `__enter__`: a chain record is created on the backend; the chain ID is available as `chain.id` after entry.

On `__aexit__` / `__exit__`: the SDK calls `POST /v1/chains/{chain_id}/complete`, which seals the chain and triggers receipt generation on the backend. If exit was triggered by an exception, the chain is marked accordingly and the receipt reflects the failure mode.

### Methods

#### `record_agent_action()` (async)

```python theme={null}
async def record_agent_action(
    self,
    agent_name: str,
    action_type: str,
    action_name: str,
    payload: dict,
    *,
    parent_agent_name: str | None = None,
    metadata: dict | None = None,
) -> PolicyDecision
```

Record an action and receive a policy decision.

| Parameter           | Type   | Description                                                                                               |
| ------------------- | ------ | --------------------------------------------------------------------------------------------------------- |
| `agent_name`        | `str`  | Identifier for the agent taking the action.                                                               |
| `action_type`       | `str`  | Category of action. Common values: `tool_call`, `llm_call`, `state_update`.                               |
| `action_name`       | `str`  | Specific name within the type. For `tool_call`, the tool name (e.g., `search_web`, `send_email`).         |
| `payload`           | `dict` | The action's inputs. Sanitized before sending.                                                            |
| `parent_agent_name` | `str`  | Agent that delegated to this one, if any. Used for tracking hierarchical workflows.                       |
| `metadata`          | `dict` | Action-level metadata. For LLM calls, include `model`, `input_tokens`, `output_tokens` for cost tracking. |

Returns a `PolicyDecision` object on `allow` or `allow_with_flag` outcomes. Blocks until resolution on `require_approval`. Raises on `deny`.

### `chain.id`

The backend-assigned chain UUID. Available after `__aenter__` / `__enter__`. Useful for logging or cross-system references:

```python theme={null}
async with proofrail.Chain("workflow") as chain:
    logger.info("Started chain", extra={"chain_id": chain.id})
```

***

## `proofrail.PolicyDecision`

Returned by `record_agent_action` when the action is allowed (including after a human approval resolves).

```python theme={null}
@dataclass
class PolicyDecision:
    policy_decision: str                          # "allow" | "allow_with_flag" | "require_approval" | "deny"
    decision_reason: str = ""
    decision_source: str = "backend_evaluation"
    policy_name: str | None = None
    kill_switch_active: bool = False
    pause_reason: str | None = None
    remediation: str | None = None
    docs_url: str | None = None
    evaluation_mode: str | None = None
    shadow_decision: str | None = None
    estimated_cost_usd: float | None = None
    auto_paused: bool = False
```

| Attribute            | Type    | Description                                                                                                                                                                                                                                                                                     |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `policy_decision`    | `str`   | The field can hold `"allow"`, `"allow_with_flag"`, `"require_approval"`, or `"deny"` — but `record_agent_action` only ever returns the object with `"allow"` or `"allow_with_flag"` here: it raises on `deny`, and blocks until resolution (then returns with `"allow"`) on `require_approval`. |
| `decision_reason`    | `str`   | Human-readable explanation if a policy matched. Empty string when no reason applies.                                                                                                                                                                                                            |
| `decision_source`    | `str`   | Where the decision came from: `"backend_evaluation"`, `"local_fast_path"`, `"human_approval"`, or `"offline_stub"`.                                                                                                                                                                             |
| `policy_name`        | `str`   | Name of the matched policy, if any.                                                                                                                                                                                                                                                             |
| `kill_switch_active` | `bool`  | True if the org's kill switch was found active during evaluation (in which case denials raise `ProofRailKillSwitchError`).                                                                                                                                                                      |
| `pause_reason`       | `str`   | If the org was paused, the reason supplied at activation.                                                                                                                                                                                                                                       |
| `remediation`        | `str`   | Suggested fix when a policy matched.                                                                                                                                                                                                                                                            |
| `docs_url`           | `str`   | Link to docs for this kind of decision.                                                                                                                                                                                                                                                         |
| `evaluation_mode`    | `str`   | `"enforce"` or `"shadow"` for the matching policy.                                                                                                                                                                                                                                              |
| `shadow_decision`    | `str`   | When `evaluation_mode` is `"shadow"`, the decision the policy would have made in enforce mode.                                                                                                                                                                                                  |
| `estimated_cost_usd` | `float` | For LLM call events, the computed cost.                                                                                                                                                                                                                                                         |
| `auto_paused`        | `bool`  | True if the chain auto-paused at this action (event-count, duration, or token-budget limit).                                                                                                                                                                                                    |

***

## Framework adapters

Each adapter exposes a `govern()` function that wraps an existing framework object. See the framework-specific pages for usage details.

### `proofrail.langgraph.govern()`

```python theme={null}
def govern(
    compiled_graph,
    chain_name: str = "langgraph_workflow",
    metadata: dict | None = None,
) -> GovernedGraph
```

See [LangGraph adapter](/frameworks/langgraph).

### `proofrail.langchain.govern()`

```python theme={null}
def govern(
    agent_executor_or_chain,
    chain_name: str = "langchain_workflow",
    metadata: dict | None = None,
) -> GovernedChain
```

The `agent_name` for recorded events is derived from `type(executor).__name__` at wrap time — it isn't a `govern()` parameter.

See [LangChain adapter](/frameworks/langchain).

### `proofrail.crewai.govern()`

```python theme={null}
def govern(
    crew,
    chain_name: str = "crewai_workflow",
    metadata: dict | None = None,
) -> GovernedCrew
```

See [CrewAI adapter](/frameworks/crewai).

### `proofrail.mcp.ProofRailMcpAdapter`

```python theme={null}
class ProofRailMcpAdapter:
    def __init__(
        self,
        *,
        chain: proofrail.Chain,
        agent_name: str,
        parent_agent_name: str | None = None,
    ): ...

    def install(self, server) -> None: ...
    async def handle_tool_call(self, tool_name: str, arguments: dict, handler) -> Any: ...
    def tool(self, tool_name: str | None = None): ...  # decorator
```

See [MCP adapter](/frameworks/mcp).

***

## `proofrail.client.verify_receipt()`

Verify a receipt's signature and return its contents.

```python theme={null}
async def verify_receipt(receipt_id: str) -> ReceiptVerifyResponse
```

```python theme={null}
class ReceiptVerifyResponse(BaseModel):
    valid: bool
    receipt_number: str
    chain_id: str
    generated_at: str
```

The `valid` field indicates whether the receipt's HMAC signature checks out. If invalid, the receipt has been tampered with or modified after signing.

This is a thin client over the public verification endpoint at `GET /v1/receipts/{receipt_id}/verify`. The endpoint requires no authentication — anyone with a receipt ID can verify.

See [Audit receipts](/concepts/audit-receipts) for the signing and hash-chaining model.

***

## Exceptions

All exceptions live in `proofrail.exceptions`. The base for policy-driven errors is `ProofRailPolicyError`.

```
ProofRailPolicyError                # base for policy denials
├── ActionDeniedError               # Policy or human reviewer denied
├── PolicyViolationError            # Policy condition violated outside main eval path
└── ProofRailKillSwitchError        # Org kill switch is active

Exception
├── BackendUnavailableError         # Backend unreachable, fail_mode=deny
├── ChainTimeoutError               # Chain exceeded configured timeout
└── ChainAutoPausedError            # Auto-pause rule fired (events, duration, tokens)
```

See [Exceptions reference](/reference/exceptions) for attributes and handling patterns.

***

## Version compatibility

The SDK requires Python 3.10 or later (enforced at install time by pip). Supported framework version ranges are pinned in `sdk/pyproject.toml`; install ProofRail with a compatible version of your framework already installed. See [Limitations](/limitations) for the current compatibility matrix.

## Where to go next

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/reference/configuration">
    Detailed walkthrough of every init() option.
  </Card>

  <Card title="Exceptions" icon="triangle-exclamation" href="/reference/exceptions">
    All exception types and how to handle them.
  </Card>

  <Card title="Framework adapters" icon="puzzle-piece" href="/frameworks/langgraph">
    Per-framework usage and edge cases.
  </Card>

  <Card title="Limitations" icon="circle-info" href="/limitations">
    What ProofRail does and doesn't do at current version.
  </Card>
</CardGroup>
