> ## 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 14: The API and HTTP Boundary

> packages/api/src/app.ts's createApp() is the single function that assembles every HTTP

## What It Is

`packages/api/src/app.ts`'s `createApp()` is the single function that assembles every HTTP
route this system exposes into one Express application, in a specific, deliberate mounting
order. Everything an external caller can reach, from an unauthenticated health check to a
signed execution request, passes through this one file's wiring.

## Why It Was Built

An HTTP API needs a consistent, auditable answer to two questions for every route: does this
route require a caller identity, and what happens when something goes wrong. `app.ts`
answers both in one place rather than leaving each route handler to decide independently,
which is what makes it possible to state precisely (not just claim) which routes are public
and why.

## How It Works

### Mounting order, and why it matters

Routes are mounted in this order, and the order is load-bearing: caller-auth middleware
(`createCallerAuthMiddleware`) is only added to the pipeline partway through, so everything
mounted before it is unauthenticated by construction, not by an exception carved out of a
uniform rule.

| Path                                                                       | Auth required                    | Why                                                                                                                                                                                      |
| -------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /health`                                                              | No                               | Liveness probe; a PaaS orchestrator has no API key to present.                                                                                                                           |
| `GET /ready`                                                               | No                               | Readiness probe (see Chapter 19); same reasoning as `/health`.                                                                                                                           |
| `GET /openapi.yaml`, `/openapi.json`                                       | No                               | A caller cannot discover how to get a key from a spec it is not allowed to read.                                                                                                         |
| `GET /api-manifest.json`                                                   | No                               | Self-description of SDK versions, same public-discovery reasoning.                                                                                                                       |
| `/documentation`, `/reference`                                             | No                               | API documentation consumers.                                                                                                                                                             |
| `POST /refusal/verify`                                                     | No                               | RFC-0021: unauthenticated, third-party signature verification, not a data-access route.                                                                                                  |
| `POST /audit/verify`                                                       | No                               | Same category as above, over `caller_audit_events` instead of Refusal Records, pure signature-over-bytes, no database lookup.                                                            |
| `/keys/:keyId`, `/.well-known/jwks.json`                                   | No                               | Public-key discovery (PQC audit RED-2); a third party verifying a signature cannot be required to already hold a credential.                                                             |
| **, caller-auth middleware mounted here if `callerAuth !== "disabled"` ,** |                                  |                                                                                                                                                                                          |
| `GET /`                                                                    | No (mounted before, but trivial) | Returns `{ name: "Parmana", status: "UP" }`.                                                                                                                                             |
| `/version`                                                                 | Yes (if auth enabled)            |                                                                                                                                                                                          |
| `/callers/me`                                                              | Yes                              | Caller self-lookup: identity and exactly what it's authorized to do.                                                                                                                     |
| `/execute`                                                                 | Yes                              | Rate-limited by `callerId` (Chapter 16); the limiter itself is only mounted when caller-auth is enabled, since there is no caller identity to key off otherwise.                         |
| `/verify`, `/verification`                                                 | Yes                              |                                                                                                                                                                                          |
| `/refusal`                                                                 | Yes                              | Ownership-scoped lookup by ID (the unauthenticated verify route above is separate).                                                                                                      |
| `/receipt`, `/receipt/latest`                                              | Yes                              |                                                                                                                                                                                          |
| `/transactions`                                                            | Yes                              |                                                                                                                                                                                          |
| `/policies`                                                                | Yes                              | Mounted twice: once for the policy-content routes (`policies.ts`), once for the Policy Governance pending-changes routes (`pending-policy-changes.ts`), their path shapes don't collide. |
| `/trust-records`                                                           | Yes                              |                                                                                                                                                                                          |
| `/replay`                                                                  | Yes                              |                                                                                                                                                                                          |
| **, error handler mounted last ,**                                         |                                  |                                                                                                                                                                                          |

(`packages/api/src/app.ts:154-347`)

### Error mapping

`createErrorHandler()` (`packages/api/src/middleware/error-handler.ts`) is the single place
a thrown domain error becomes an HTTP response:

| Thrown                                                                                 | Status                        | Notes                                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Malformed/oversized JSON body (`express.json()`, before any route handler)             | 400 / 413                     | Best-effort audited even though no caller identity exists yet (G-29), deliberately fail-**open** here, unlike every other caller-audit write, since the correct rejection has already happened by the time this fires. |
| `BusinessTransactionValidationError`, `PolicyValidationError`, `SignalValidationError` | 400                           |                                                                                                                                                                                                                        |
| `PolicyNotFoundError`                                                                  | 404                           |                                                                                                                                                                                                                        |
| `DuplicateBusinessTransactionError`                                                    | 409                           |                                                                                                                                                                                                                        |
| `NonceAlreadyConsumedError`                                                            | `error.status` (its own code) | Distinguished from a generic `RuntimeError` so a caller can tell "this already ran" apart from "something broke" without string-matching a 500 body.                                                                   |
| Any `RuntimeError`                                                                     | `error.status`                |                                                                                                                                                                                                                        |
| Anything else                                                                          | 500                           | Logged via `console.error`, response body is the generic `"Internal Server Error"`, no internal detail leaked.                                                                                                         |

(`packages/api/src/middleware/error-handler.ts:95-201`)

### The full route inventory

Every route module lives in `packages/api/src/routes/`:

| File                                | Mounted at                               | Purpose                                                           |
| ----------------------------------- | ---------------------------------------- | ----------------------------------------------------------------- |
| `health.ts`                         | `/health`                                | Liveness.                                                         |
| `ready.ts`                          | `/ready`                                 | Readiness (Chapter 19).                                           |
| `openapi.ts` / `openapi-json.ts`    | `/openapi.yaml` / `/openapi.json`        | Machine-readable API spec.                                        |
| `api-manifest.ts`                   | `/api-manifest.json`                     | SDK version self-description.                                     |
| `documentation.ts` / `reference.ts` | `/documentation` / `/reference`          | Human-readable docs.                                              |
| `refusal-verify.ts`                 | `/refusal/verify`                        | Public signature verification of a Refusal Record.                |
| `audit-verify.ts`                   | `/audit/verify`                          | Public signature verification of an audit event.                  |
| `keys.ts`                           | `/keys/:keyId`, `/.well-known/jwks.json` | Public key discovery.                                             |
| `callers-me.ts`                     | `/callers/me`                            | Caller self-lookup.                                               |
| `execute.ts`                        | `/execute`                               | Submit and execute a Business Transaction.                        |
| `verify.ts` / `verify-get.ts`       | `/verify` / `/verification`              | Verification of an executed transaction.                          |
| `refusal-get.ts`                    | `/refusal`                               | Ownership-scoped Refusal Record lookup.                           |
| `receipt.ts` / `receipt-get.ts`     | `/receipt` / `/receipt/latest`           | Receipt issuance and lookup.                                      |
| `transactions.ts`                   | `/transactions`                          | Business Transaction create-and-execute (parity with `/execute`). |
| `policies.ts`                       | `/policies`                              | Policy content read/validate routes.                              |
| `pending-policy-changes.ts`         | `/policies`                              | Maker-checker propose/list/approve/reject (Chapter 7).            |
| `trust-records.ts`                  | `/trust-records`                         | Bulk export.                                                      |
| `replay.ts`                         | `/replay`                                | Replay a prior execution.                                         |
| `version.ts`                        | `/version`                               |                                                                   |
| `findOpenApiSpecFile.ts`            | (helper, not a route)                    | Locates the built OpenAPI spec file on disk.                      |

### `trust proxy`

`app.set("trust proxy", 1)` (`packages/api/src/app.ts:147`) trusts exactly one proxy hop ,
this codebase's actual deployment fronting (Fly.io's edge, per `fly.toml`'s
`force_https`). Without this, `req.ip` and `req.protocol`/`req.secure` reflect the proxy's
own connection to the process, not the original client's.

## How It Enables Things, With a Concrete Example

`examples/tutorials/102-distinguishable-http-status` demonstrates the `NonceAlreadyConsumedError`
vs. generic-`RuntimeError` distinction in the error handler directly, a policy denial and a
replay attempt against the same endpoint return genuinely different, distinguishable status
codes rather than both collapsing into an opaque failure.

## How to Validate This Yourself

* `packages/api/src/app.ts`, the actual mounting order; read it top to bottom rather than
  trusting the table above once this file changes.
* `packages/api/src/middleware/error-handler.ts`, the full error-to-status mapping.
* `packages/api/src/routes/*.ts`, one file per route group.
* `packages/api/tests/integration/*.integration.test.ts`, most route groups have a
  corresponding integration test that exercises the real HTTP path, not just the handler
  function in isolation.

## Integration Requirements

`createApp()` requires a `CallerAuthOption`, either a real `{ authenticator, auditSink }`
pair or the literal string `"disabled"` (used only for local development and the tutorial
suite; there is deliberately no default, so omitting this choice is not possible). Optional:
`RateLimitOption` (Chapter 16), `stepUpVerifier` and `policyChangeApprovalService` (both
required in effect, though optional at the type level, once caller-auth is enabled and the
Policy Governance approve/reject endpoints are actually reachable, see Chapter 7).
