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

# APIs & Models

> Every Python sub-API and model, cross-checked against the TypeScript SDK for parity

## APIs

Each sub-API is a small class over the shared `Transport` (`python/parmana/config/transport.py`, an ABC), one module per concern under `python/parmana/api/`. Every class's docstring lists what it explicitly does **not** do — the same convention used in the TypeScript SDK.

### ExecutionApi

```python theme={null}
class ExecutionApi:
    def health(self) -> dict: ...                                    # GET /health
    def execute(self, transaction: BusinessTransaction) -> ExecutionTrustRecord: ...  # POST /execute
```

`execute()` runs the transaction through `encode()` (`python/parmana/serialization/encoder.py`) first, converting the dataclass's snake\_case fields to the camelCase JSON the Runtime expects, and decodes the response back into `ExecutionTrustRecord` via `response_model=`.

### VerificationApi

```python theme={null}
class VerificationApi:
    def verify(self, business_transaction_id: str) -> Verification: ...  # POST /verify
```

<Warning>
  **Divergence from TypeScript.** Python's `verify()` calls `POST /verify` — it **triggers** a new Verification. TypeScript's `verify()` calls `GET /verification/:id` — it **reads** the latest one. See [ParmanaClient → verify() does not mean the same thing](/docs/python-sdk/parmana-client#verify-does-not-mean-the-same-thing-in-both-sdks) for the full explanation. This is the one place the two SDKs' public surfaces are not just differently shaped but behaviorally different.
</Warning>

### ReplayApi

```python theme={null}
class ReplayApi:
    def replay(self, business_transaction_id: str) -> ReplayResult: ...  # POST /replay
```

Matches TypeScript's `ReplayApi.replay()` — both call `POST /replay` and type the result as the flat `{business_transaction_id, trust_record_hash, verified}` shape. See [REST API → Replay](/docs/api/replay) for what this endpoint actually checks (a hash comparison, not deterministic policy re-evaluation via the `replay` package).

### ReceiptApi

```python theme={null}
class ReceiptApi:
    def generate(self, business_transaction_id: str) -> Receipt: ...  # POST /receipt
```

Matches TypeScript: only `generate()` exists. Neither SDK has a method for `GET /receipt/latest/:id` — see [REST API → Receipt](/docs/api/receipt#get-the-latest-receipt).

### TransactionApi

```python theme={null}
class TransactionApi:
    def get(self, business_transaction_id: str) -> BusinessTransaction: ...             # GET /transactions/:id
    def list(self, *, page: int = 1, page_size: int = 25) -> list[BusinessTransaction]: ...  # GET /transactions
```

Matches TypeScript's `TransactionApi` one-for-one, aside from naming (`page_size` vs. `pageSize`, per each language's convention).

### TrustRecordApi

```python theme={null}
class TrustRecordApi:
    def get(self, business_transaction_id: str) -> ExecutionTrustRecord: ...  # GET /trust-records/:id
```

Matches TypeScript's `TrustRecordApi` exactly.

### PolicyApi

```python theme={null}
class PolicyApi:
    def validate(self, policy: dict) -> dict: ...  # POST /policies/validate
```

Python's `validate()` takes and returns a plain `dict` — there's no `PolicyReference`/`Policy` dataclass involved at all, unlike TypeScript's `PolicyApi.validate()` which is typed against the `Policy` interface from `@parmana/policy`. Functionally equivalent (the server only reads `policyId`/`policyVersion` off the body either way), just untyped on the Python side.

## Models

`python/parmana/models/` defines one `@dataclass(frozen=True)` per domain concept. Field names are `snake_case` Python equivalents of the same camelCase fields used by the Runtime and by the TypeScript SDK's models — `encode()`/`decode()` (`python/parmana/serialization/`) convert between the two automatically using regex-based case conversion, both directions.

| Model                                                | File                                                                 | TypeScript equivalent                                |
| ---------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------- |
| `Authority`                                          | `authority.py`                                                       | `Authority`                                          |
| `Authorization`                                      | `authorization.py`                                                   | `Authorization`                                      |
| `Intent`                                             | `intent.py`                                                          | `Intent`                                             |
| `BusinessTransaction`, `BusinessTransactionMetadata` | `business_transaction.py`                                            | `BusinessTransaction`, `BusinessTransactionMetadata` |
| `Decision`, `Execution`                              | `execution.py`                                                       | `Decision`, `Execution`                              |
| `Override`                                           | `override.py`                                                        | `Override`                                           |
| `PolicyReference`                                    | `policy.py`                                                          | `PolicyReference`                                    |
| `Receipt`                                            | `receipt.py`                                                         | `Receipt`                                            |
| `ReplayResult`                                       | `replay_result.py` (also duplicated verbatim in `replay.py`, unused) | `ReplayResult`                                       |
| `ExecutionTrustRecord`                               | `trust_record.py`                                                    | `ExecutionTrustRecord`                               |
| `Verification`                                       | `verification.py`                                                    | `Verification`                                       |

Field-for-field, every model here matches its TypeScript counterpart. The one duplicate is `models/replay.py`, which defines a byte-for-byte identical `ReplayResult` dataclass to `models/replay_result.py` — `replay_api.py` imports from `replay_result.py`, so `replay.py`'s copy is unused dead code, not a second, different result type.

<Note>
  Only `Authority`, `Authorization`, `Intent`, `PolicyReference`, `BusinessTransaction`, `BusinessTransactionMetadata`, `Verification`, `Receipt`, `ReplayResult`, and `ExecutionTrustRecord` are re-exported from the top-level `parmana` package (`python/parmana/__init__.py`). `Execution`, `Decision`, and `Override` are not — import them from `parmana.models.execution` / `parmana.models.override` directly.
</Note>

### `Override` has the same drift as TypeScript

`python/parmana/models/override.py` uses `authority_id`, matching the TypeScript SDK's (also drifted) field name — but the canonical domain type (`packages/shared/src/domain/override.ts`) actually has `approved_by`/`approvedBy`, plus an optional `justification` neither SDK models at all. See [TypeScript SDK → Models](/docs/typescript-sdk/models#override-has-drifted-from-the-canonical-domain-model) for the full comparison. Since neither SDK — nor the REST API — exposes any way to create or fetch an `Override` today (see [Guides → Human Override](/docs/guides/human-override)), this drift has no observable effect yet.

### Timestamps are handled better than in TypeScript

`decode()` (`python/parmana/serialization/decoder.py`) parses every `datetime`-typed field with `datetime.fromisoformat(value.replace("Z", "+00:00"))`, so timestamps really do arrive as Python `datetime` objects. This is a genuine advantage over the TypeScript SDK, whose models declare fields as `Date` but never actually construct one — see [TypeScript SDK → Models](/docs/typescript-sdk/models#field-types).

## Errors

Python's error hierarchy is much smaller than TypeScript's, and behaves differently:

| Class          | `code`             | Raised when                                                                            |
| -------------- | ------------------ | -------------------------------------------------------------------------------------- |
| `ApiError`     | `API_ERROR` (base) | Never raised directly.                                                                 |
| `NetworkError` | `NETWORK_ERROR`    | `requests.exceptions.RequestException` (`python/parmana/transport/http_transport.py`). |
| `RuntimeError` | `RUNTIME_ERROR`    | Any non-`2xx` HTTP response.                                                           |

```python theme={null}
from parmana.errors import ApiError, NetworkError, RuntimeError
```

<Warning>
  **`RuntimeError` shadows Python's built-in `RuntimeError`.** `python/parmana/errors/runtime_error.py` defines `class RuntimeError(ApiError)` in its own module namespace. `from parmana.errors import RuntimeError` (or `from parmana import errors; errors.RuntimeError`) shadows the built-in name in whatever scope you import it into — `except RuntimeError` after that import catches only Parmana's SDK error, not Python's built-in one. Import it under an alias (`from parmana.errors import RuntimeError as ParmanaRuntimeError`) if you need both in the same file.
</Warning>

<Warning>
  **This is the opposite of the TypeScript SDK's error-handling gap.** `HttpTransport._parse_response` checks `response.ok` and raises `RuntimeError(message, request_id=...)` — pulling `message` from the response body's `error` or `message` field — for every non-2xx status. This means the Python SDK **does** turn HTTP error responses into exceptions, unlike the TypeScript SDK, whose `HttpTransport` resolves successfully regardless of status code (see [TypeScript SDK → Errors](/docs/typescript-sdk/errors)). If you're porting error-handling logic from one SDK to the other, this is not a safe assumption to carry over.
</Warning>

## Related

<CardGroup cols={2}>
  <Card title="ParmanaClient" href="/docs/python-sdk/parmana-client">The facade composing these APIs.</Card>
  <Card title="TypeScript SDK" href="/docs/typescript-sdk/apis">The equivalent TypeScript surface, for comparison.</Card>
  <Card title="Error Model (REST API)" href="/docs/api/error-model">What the server actually returns on failure.</Card>
  <Card title="Concepts" href="/docs/concepts/overview">The domain concepts these models represent.</Card>
</CardGroup>
