> ## 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.

# Express.js Integration

> Add governance to an Express.js API

## Install

```bash theme={null}
npm install @parmanasystems/core express
npm install --save-dev @types/express
```

## Setup

Initialize governance once at startup and inject it into your route handlers:

```typescript theme={null}
import crypto from "crypto";
import express from "express";
import {
  executeFromSignals,
  verifyAttestation,
  LocalSigner,
  LocalVerifier,
  MemoryReplayStore,
} from "@parmanasystems/core";

// Initialize once at startup - not per-request
const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519", {
  privateKeyEncoding: { type: "pkcs8", format: "pem" },
  publicKeyEncoding:  { type: "spki",  format: "pem" },
});

const signer   = new LocalSigner(privateKey);
const verifier = new LocalVerifier(publicKey);
const store    = new MemoryReplayStore(); // Use RedisReplayStore in production

const app = express();
app.use(express.json());

app.post("/govern", async (req, res) => {
  try {
    const { policyId, policyVersion, signals } = req.body;

    const attestation = await executeFromSignals(
      { policyId, policyVersion, signals },
      signer,
      verifier,
      undefined,
      store
    );

    res.json({
      decision:    attestation.decision,
      executionId: attestation.executionId,
      verified:    verifyAttestation(attestation, verifier).valid,
    });
  } catch (error: any) {
    const code = error.message.match(/\[([\w-]+)@/)?.[1];
    res.status(code === "INV-013" ? 409 : 400).json({
      error: error.message,
      code,
    });
  }
});

app.listen(3000, () => console.log("Governance server on :3000"));
```

## Error handling

Governance errors are thrown by `executeFromSignals`. Map them to HTTP status codes:

| Error                   | HTTP | Cause                               | Fix                                                |
| ----------------------- | ---- | ----------------------------------- | -------------------------------------------------- |
| `Policy not found: ...` | 400  | Wrong `policyId` or `policyVersion` | Check `policies/{id}/{version}/policy.json` exists |
| `VAL-003`               | 400  | Unknown signal in input             | Remove the signal or add it to `signalsSchema`     |
| `VAL-004`               | 400  | Required signal missing             | Add the missing signal to the request              |
| `VAL-006` - `VAL-012`   | 400  | Signal has wrong type               | Check declared types in `signalsSchema`            |
| `INV-013`               | 409  | Replay detected                     | Each signal set executes exactly once              |

## Using the standalone server

For production deployments, consider using `@parmanasystems/server` — a ready-to-deploy Fastify server with Redis replay store, PostgreSQL audit persistence, and a full set of governance endpoints built in. Configure it via environment variables and run it directly:

```bash theme={null}
PORT=3000 PARMANA_SIGNING_KEY="$PRIVATE_KEY" node node_modules/@parmanasystems/server/dist/index.js
```

See the [Server Package](/packages/server) for the full list of environment variables and endpoints.

## Production notes

Replace `MemoryReplayStore` with `RedisReplayStore` and load keys from environment variables or a secrets manager. See the [Production Checklist](/guides/production-checklist) for the full list.

## See also

* [Server Package](/packages/server) - the full standalone governance server
* [SDK Client Package](/packages/sdk-client) - HTTP client for the server
* [Production Checklist](/guides/production-checklist)
