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

# Chapter 20: Integrating Parmana (Requirements and Getting Started)

> Integrating Parmana means getting a caller, human, AI agent, or automated service, to submit a

## What it is

Integrating Parmana means getting a caller, human, AI agent, or automated service, to submit a
Business Transaction to a running Parmana instance and receive back a signed Execution Trust
Record. There are three real paths to do this: the official TypeScript SDK (`typescript/`,
published as `@parmana/sdk`), the official Python SDK (`python/`, published as `parmana`), or
plain HTTP against the REST API directly. All three ultimately call the same two routes,
`POST /execute` and `POST /transactions`, which run through the identical execution pipeline.

## Why it was built this way

A caller hand-building a request body has to keep three id pairs internally consistent
(`metadata.businessTransactionId` must equal the top level `businessTransactionId`,
`authorization.authorityId` must equal `authority.authorityId`, `intent.authorizationId` must
equal `authorization.authorizationId`). Getting any of these wrong produces a 400 from
`BusinessTransactionValidator`. The SDKs exist specifically to make that class of mistake
structurally impossible, not merely documented. `typescript/src/builders/createBusinessTransaction.ts`
says this directly in its own doc comment: this exact mismatch is "the class of mistake that
produced every 'X must match Y' 400 response documented in `END-TO-END-FLOW.md`."

## How it works

### The TypeScript SDK

`@parmana/sdk`'s entry point is `ParmanaClient` (`typescript/src/client/ParmanaClient.ts`). Its
own doc comment is explicit about what it does and does not do: it holds configuration, composes
sub-APIs, and delegates, it does not evaluate policy, authorize execution, execute business
logic, verify trust records, or replay executions, all of that is server side.

Construction requires a `Configuration` (`typescript/src/config/Configuration.ts`):

```ts theme={null}
interface Configuration {
  readonly endpoint: string; // Parmana Runtime endpoint, e.g. https://runtime.example.com
  readonly apiKey?: string; // Bearer key minted by scripts/generate-api-key.ts
  readonly timeout?: number; // default 30000ms
  readonly retryPolicy?: RetryPolicy;
  readonly transport?: Transport; // defaults to the SDK's own HTTP transport
  readonly userAgent?: string;
}
```

`apiKey` is optional only against a Runtime started with `PARMANA_AUTH_DISABLED=true`, which is
local development only, every other deployment rejects an unauthenticated request with a 401
before a Business Transaction is even constructed.

`ParmanaClient` composes ten sub APIs (`HealthApi`, `ExecutionApi`, `VerificationApi`,
`ReplayApi`, `ReceiptApi`, `TransactionApi`, `TrustRecordApi`, `PolicyApi`, `RefusalApi`,
`AuditApi`), each a thin wrapper over one or more HTTP calls through the shared `Transport`. The
public surface includes `execute()`, `createTransaction()` (a second, independent entry point
into the identical pipeline via `POST /transactions`), `verify()`, `getLatestVerification()`,
`replay()`, `receipt()`, `transaction()`/`transactions()`, `trustRecord()`, `validatePolicy()`,
`refusalRecord()`/`verifyRefusalRecord()`, and `verifyAuditEvent()`.

`createBusinessTransaction()` (`typescript/src/builders/createBusinessTransaction.ts`) is the
recommended way to build a request body. It takes the fields a caller actually decides
(`principalId`, `purpose`, `action`, `target`, `parameters`, `policy`, `signals`, and optional
`businessTransactionId`, `authorityType`, `correlationId`, `tenantId`, `sourceSystem`,
`submittedBy`) and derives every id-consistency field automatically. `authorityType` defaults to
`"SERVICE"`, described in the source as "the correct value for an autonomous agent" (there is no
`"AGENT"` value server side, a common first-integration mistake). `businessTransactionId`
defaults to a fresh `crypto.randomUUID()` if omitted, and if you provide your own, you are
responsible for its uniqueness, since it doubles as the server's idempotency key.

### The Python SDK

`python/parmana/client.py` mirrors the same shape: a `ParmanaClient`, a `ClientConfig`
(`python/parmana/config/client_config.py`), and a parallel set of API modules under
`python/parmana/api/` (`execution_api.py`, `policy_api.py`, `transaction_api.py`,
`trust_record_api.py`, `verification_api.py`, `replay_api.py`, `receipt_api.py`,
`refusal_api.py`, `audit_api.py`). `python/parmana/builders.py` is the equivalent of the
TypeScript builder. Requires Python 3.10+ (from `pyproject.toml`'s `requires-python`).

### The plain HTTP path

Every SDK call ultimately becomes an HTTP request. A minimal integration with no SDK at all
needs:

1. A bearer key: `Authorization: Bearer <key>` on every request except `/health`, `/ready`,
   `/openapi.yaml`, `/openapi.json`, `/api-manifest.json`, `/documentation`, `/reference`,
   `/refusal/verify`, `/audit/verify`, and the key-discovery routes.
2. A policy that already exists on the target instance, at the exact `(name, version)` you
   reference, and (if `POLICY_EXECUTION_VERIFICATION_ENFORCED=true` on that instance) has a real
   `PolicyChangeApprovalRecord` (see Chapter 7).
3. A well formed `BusinessTransaction` body, with every fact your chosen policy's rules
   reference present in `signals`, matching either a `boundSignals` entry (derived automatically
   from `target`/`parameters` server side, but still worth sending consistently) or an
   `unboundSignalReasons` entry (must be supplied directly).

## Concrete example

`examples/tutorials/` has dedicated SDK walkthroughs (grep `examples/tutorials/` for `sdk` in the
directory name): the TypeScript and Python quickstart, AI-agent, and production-pattern
tutorials each demonstrate a real client construction and a real `execute()` call against a
locally spun-up server, no live network needed. `docs/site/guides/typescript-sdk-quickstart.mdx`
and `docs/site/guides/python-sdk-quickstart.mdx` cover the same ground for the docs site; their
code samples were checked against the actual SDK source above, not copied blind.

## How to validate this yourself

* `typescript/src/client/ParmanaClient.ts`, `typescript/src/config/Configuration.ts`,
  `typescript/src/builders/createBusinessTransaction.ts`, `typescript/test/` for the SDK's own
  test suite.
* `python/parmana/client.py`, `python/parmana/config/client_config.py`,
  `python/parmana/builders.py`, `python/tests/`.
* `packages/runtime/src/validators/BusinessTransactionValidator.ts` for the exact
  cross-consistency checks a hand built transaction must satisfy.
* `END-TO-END-FLOW.md` (repo root) for the original incident record of what happens when these
  checks fail.

## Requirements checklist

**On the caller side, to make any real call:**

* A bearer key, provisioned via `npx tsx scripts/generate-api-key.ts --caller-id "<you>" --credential-holder-type <TYPE>`. `credentialHolderType` must be `USER` if you intend to act as
  a policy governance checker (Chapter 7); `SERVICE` is typical for an automated integration.
* `allowedPrincipalIds`, if your key is scoped to specific principals, must include whatever
  `principalId` you submit, or the request is rejected before policy runs. Check with
  `GET /callers/me`.
* `allowedCapabilities`, if scoped, must include the `action` capability you intend to invoke.

**On the server/instance side, verified against `.env.example` and `packages/shared/src/config/Config.ts`:**

| Variable                                                                                                                                              | Purpose                                                                                                                                                            |
| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `PARMANA_POLICY_DIR`                                                                                                                                  | Local policy file directory (used when storage is not Supabase backed).                                                                                            |
| `PARMANA_KEY_DIR` / `PARMANA_KEY_MATERIAL_JSON`                                                                                                       | Local Ed25519 key material (`KEY_PROVIDER=local`).                                                                                                                 |
| `PARMANA_STORAGE`                                                                                                                                     | `memory` or `supabase`. `supabase` requires `DATABASE_URL`.                                                                                                        |
| `DATABASE_URL`                                                                                                                                        | Direct Postgres connection string (Supabase or otherwise), used by `pg`, not PostgREST.                                                                            |
| `SUPABASE_URL` / `SUPABASE_SERVICE_ROLE_KEY` / `SUPABASE_ANON_KEY`                                                                                    | Only needed for the handful of code paths that still use the Supabase client directly (e.g. CI's read-only policy verification script), not the main request path. |
| `CRYPTO_MODE`, `PRIMARY_SIGNATURE_PROVIDER`, `SECONDARY_SIGNATURE_PROVIDER`, `HASH_PROVIDER`                                                          | Signature/hash algorithm selection (see Chapter 3).                                                                                                                |
| `KEY_PROVIDER`                                                                                                                                        | `local` is the only implemented value as of this writing; anything else throws explicitly (`KeyBootstrap.create()`).                                               |
| `AWS_REGION`, `AWS_ROLE_ARN`                                                                                                                          | Required only when using real AWS KMS signing (`KmsSigner.ts`), via Vercel OIDC, no static AWS credentials needed.                                                 |
| `EXECUTION_AUTHORIZATION_TTL_SECONDS`                                                                                                                 | Default 120.                                                                                                                                                       |
| `PARMANA_API_KEYS`                                                                                                                                    | JSON array of caller entries, the live authentication table.                                                                                                       |
| `RATE_LIMIT_EXECUTE_PER_MINUTE`, `RATE_LIMIT_HEALTH_PER_MINUTE`                                                                                       | Rate limiting (Chapter 16).                                                                                                                                        |
| `HUBSPOT_PRIVATE_APP_TOKEN`, `GITHUB_APP_ID`/`GITHUB_INSTALLATION_ID`/`GITHUB_APP_PRIVATE_KEY`, `PAYTM_CONNECTOR_URL`/`PAYTM_CONNECTOR_SHARED_SECRET` | Only needed if you intend to exercise the corresponding connector (Chapter 12); a connector is simply not registered if its config is unset, nothing else fails.   |

## Common first-integration mistakes

* Sending `authorityType: "AGENT"`, which does not exist server side; use `"SERVICE"`.
* Hand-building the three id-consistency fields instead of using `createBusinessTransaction()`,
  and getting one wrong.
* Forgetting that `businessTransactionId` is an idempotency key: resubmitting the same id with
  different content is rejected as a duplicate before execution, not silently overwritten (see
  `docs/site/guides/end-to-end-paytm-flow.mdx`).
* Referencing a policy `(name, version)` that exists on disk but has never been approved, on an
  instance where `POLICY_EXECUTION_VERIFICATION_ENFORCED=true` (Chapter 7). On most current
  deployments this flag is off, so this specific failure mode is currently latent, not active,
  but worth knowing about before it's turned on.
* Omitting a `signals` entry for a fact the target policy's rules actually reference; the request
  is rejected, not silently evaluated with a missing/undefined fact.
