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

# AI Agent Wants To Send Money

> An AI agent can request a payment. Parmana verifies authority before execution.

## Scenario

An AI agent wants to send money.

The agent identifies a recipient.

The agent determines an amount.

The agent prepares a payment request.

The agent can generate intent.

The agent does not possess authority.

Authority is defined by humans through policy.

Before money moves, Parmana verifies that the requested payment complies with human-defined authority requirements.

If authority is verified:

* A signed attestation is issued
* The payment may proceed
* The decision can be independently verified later

If authority is not verified:

* The payment is blocked
* No money moves
* The failure is auditable

The payment processor does not trust the AI agent.

The payment processor trusts a valid authority verification attestation.

This example demonstrates the core Parmana principle:

**AI Has Intelligence.**

**Humans Have Authority.**

**Parmana Verifies Authority Before Execution.**

***

## Policy

Create `policies/payment-approval/1.0.0/policy.json`:

```json theme={null}
{
  "policyId": "payment-approval",
  "policyVersion": "1.0.0",
  "schemaVersion": "1.0.0",
  "signalsSchema": {
    "amount":              { "type": "number" },
    "currency":            { "type": "string" },
    "merchantCategory":    { "type": "string" },
    "accountAge":          { "type": "integer" },
    "fraudScore":          { "type": "number" },
    "velocityCount24h":    { "type": "integer" },
    "countryRisk":         { "type": "string" }
  },
  "rules": [
    {
      "id": "block-high-fraud",
      "condition": { "signal": "fraudScore", "greater_than": 0.8 },
      "outcome": {
        "action": "reject",
        "requires_override": false,
        "reason": "Transaction blocked: fraud score exceeds maximum threshold."
      }
    },
    {
      "id": "block-high-velocity",
      "condition": { "signal": "velocityCount24h", "greater_than": 20 },
      "outcome": {
        "action": "reject",
        "requires_override": false,
        "reason": "Transaction blocked: velocity limit exceeded."
      }
    },
    {
      "id": "hold-large-transaction",
      "condition": { "signal": "amount", "greater_than": 10000 },
      "outcome": {
        "action": "hold",
        "requires_override": true,
        "reason": "Transaction held for manual review: amount exceeds auto-approval limit."
      }
    },
    {
      "id": "hold-high-risk-country",
      "condition": { "signal": "countryRisk", "equals": "HIGH" },
      "outcome": {
        "action": "hold",
        "requires_override": true,
        "reason": "Transaction held: high-risk country of origin."
      }
    },
    {
      "id": "approve-standard",
      "condition": { "all": [] },
      "outcome": {
        "action": "approve",
        "requires_override": false,
        "reason": "Transaction approved: within standard parameters."
      }
    }
  ]
}
```

***

## Complete TypeScript example

```typescript theme={null}
import { ParmanaClient, ParmanaApiError } from "@parmanasystems/sdk-client";
import type { ExecutionAttestation } from "@parmanasystems/sdk-client";

const client = new ParmanaClient({
  baseUrl: process.env.PARMANA_URL ?? "http://localhost:3000",
  apiKey: process.env.PARMANA_API_KEY,
});

interface PaymentSignals {
  amount: number;
  currency: string;
  merchantCategory: string;
  accountAge: number;      // days
  fraudScore: number;      // 0.0–1.0
  velocityCount24h: number;
  countryRisk: "LOW" | "MEDIUM" | "HIGH";
}

interface PaymentAuthResult {
  transactionId: string;
  authorized: boolean;
  action: string;
  reason: string;
  requiresHold: boolean;
  attestationSignature: string;
}

async function authorizePayment(
  transactionId: string,
  signals: PaymentSignals
): Promise<PaymentAuthResult> {
  const attestation = await client.execute({
    executionId: transactionId,  // transaction ID IS the executionId — must be globally unique
    policyId: "payment-approval",
    policyVersion: "1.0.0",
    signals,
  });

  // Always verify before authorizing — fail closed
  const verification = await client.verify(attestation);
  if (!verification.valid) {
    return {
      transactionId,
      authorized: false,
      action: "reject",
      reason: "Governance attestation could not be verified. Payment blocked.",
      requiresHold: false,
      attestationSignature: "",
    };
  }

  const authorized =
    attestation.execution_state === "completed" &&
    attestation.decision.action === "approve";

  return {
    transactionId,
    authorized,
    action: attestation.decision.action,
    reason: attestation.decision.reason,
    requiresHold: attestation.execution_state === "pending_override",
    attestationSignature: attestation.signature,
  };
}

// Post-execution confirmation — prove the payment matched the authorization
async function confirmPaymentExecuted(
  transactionId: string,
  attestation: ExecutionAttestation,
  paymentDetails: {
    amount: number;
    currency: string;
    recipientAccountId: string;
  }
) {
  const proof = await client.confirmExecution({
    attestation,
    executedAction: {
      actionType: "payment_transfer",
      actionId: transactionId,
      actionTimestamp: new Date().toISOString(),
      actionDetails: paymentDetails,
    },
    timeWindowSeconds: 60,  // action must occur within 60 seconds of authorization
  });

  return proof;
}

// Example usage
async function main() {
  // Standard approval
  const approved = await authorizePayment("TXN-20240115-0001", {
    amount: 250,
    currency: "USD",
    merchantCategory: "retail",
    accountAge: 730,
    fraudScore: 0.02,
    velocityCount24h: 3,
    countryRisk: "LOW",
  });
  console.log(approved.action);     // "approve"
  console.log(approved.authorized); // true

  // Rejected: fraud score
  const blocked = await authorizePayment("TXN-20240115-0002", {
    amount: 500,
    currency: "USD",
    merchantCategory: "electronics",
    accountAge: 90,
    fraudScore: 0.92,
    velocityCount24h: 15,
    countryRisk: "LOW",
  });
  console.log(blocked.action);     // "reject"
  console.log(blocked.authorized); // false

  // Hold: large transaction
  const held = await authorizePayment("TXN-20240115-0003", {
    amount: 15000,
    currency: "USD",
    merchantCategory: "wire_transfer",
    accountAge: 1200,
    fraudScore: 0.05,
    velocityCount24h: 1,
    countryRisk: "LOW",
  });
  console.log(held.action);       // "hold"
  console.log(held.requiresHold); // true
}

main().catch(console.error);
```

***

## Handling held transactions

When `requiresHold` is `true`, route the transaction to a compliance officer:

```typescript theme={null}
const resolution = await client._request<{
  status: string;
  overrideId: string;
}>("/override", {
  method: "POST",
  body: JSON.stringify({
    executionId: "TXN-20240115-0003",
    approved: true,
    approvedBy: "compliance-officer-james-wu",
    approverRole: "compliance_officer",
    reason: "Wire transfer verified: known business account, documented purpose.",
  }),
});

console.log(resolution.status);     // "approved"
console.log(resolution.overrideId); // ID of the override record
```

***

## Expected results

| Signals                         | Expected `action` | `requires_override` |
| ------------------------------- | ----------------- | ------------------- |
| `fraudScore: 0.02, amount: 250` | `approve`         | `false`             |
| `fraudScore: 0.92`              | `reject`          | `false`             |
| `velocityCount24h: 25`          | `reject`          | `false`             |
| `amount: 15000`                 | `hold`            | `true`              |
| `countryRisk: "HIGH"`           | `hold`            | `true`              |

***

## Troubleshooting

**`[INV-013@replay] Replay detected`** Each `transactionId` is used as the `executionId`. Once a transaction is authorized, it cannot be re-authorized with the same ID. Generate a new transaction ID for retries.

**`execution_state: "pending_override"` but `action: "approve"`** A policy rule can set `action: "approve"` with `requires_override: true`. The convention is to use a distinct action name (e.g., `"hold"`) when override is required, but it is not enforced. Always check both `execution_state` and `decision.action`.

**Payment executed without attestation verification** Always call `client.verify()` before authorizing a transfer. If verification fails, block the payment and investigate.
