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

# Customer Refund Authorization

> Govern refund decisions with policy-based authorization and audit trail

## Scenario

A customer service platform processes refund requests. Refund decisions must be governed to prevent unauthorized payouts, ensure policy compliance, and create an auditable trail for finance and compliance teams.

Requirements:

* Small refunds auto-approved within policy limits
* Large or repeat refunds require supervisor sign-off
* Every refund decision is signed and referenceable in the accounting system
* Customer service agents cannot modify or replay refund authorizations

***

## Policy

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

```json theme={null}
{
  "policyId": "refund-approval",
  "policyVersion": "1.0.0",
  "schemaVersion": "1.0.0",
  "signalsSchema": {
    "refundAmount":          { "type": "number" },
    "orderAge":              { "type": "integer" },
    "customerRefundCount":   { "type": "integer" },
    "refundReason":          { "type": "string" },
    "originalOrderAmount":   { "type": "number" },
    "accountStanding":       { "type": "string" }
  },
  "rules": [
    {
      "id": "deny-expired",
      "condition": { "signal": "orderAge", "greater_than": 90 },
      "outcome": {
        "action": "reject",
        "requires_override": false,
        "reason": "Refund denied: order age exceeds 90-day return policy."
      }
    },
    {
      "id": "deny-bad-standing",
      "condition": { "signal": "accountStanding", "equals": "suspended" },
      "outcome": {
        "action": "reject",
        "requires_override": false,
        "reason": "Refund denied: account is suspended."
      }
    },
    {
      "id": "review-high-value",
      "condition": { "signal": "refundAmount", "greater_than": 500 },
      "outcome": {
        "action": "supervisor_review",
        "requires_override": true,
        "reason": "Refund requires supervisor approval: amount exceeds auto-approval threshold."
      }
    },
    {
      "id": "review-repeat-refunds",
      "condition": { "signal": "customerRefundCount", "greater_than": 3 },
      "outcome": {
        "action": "supervisor_review",
        "requires_override": true,
        "reason": "Refund requires supervisor review: customer has exceeded refund frequency."
      }
    },
    {
      "id": "auto-approve",
      "condition": { "all": [] },
      "outcome": {
        "action": "approve",
        "requires_override": false,
        "reason": "Refund approved within standard policy limits."
      }
    }
  ]
}
```

***

## Complete TypeScript example

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

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

interface RefundSignals {
  refundAmount: number;
  orderAge: number;            // days since order
  customerRefundCount: number; // refunds in last 90 days
  refundReason: string;
  originalOrderAmount: number;
  accountStanding: "good" | "warned" | "suspended";
}

interface RefundResult {
  refundId: string;
  approved: boolean;
  pendingSupervisor: boolean;
  action: string;
  reason: string;
  attestationSignature: string;
}

async function requestRefund(
  refundId: string,
  signals: RefundSignals
): Promise<RefundResult> {
  const attestation = await client.execute({
    executionId: refundId,
    policyId: "refund-approval",
    policyVersion: "1.0.0",
    signals,
  });

  // Verify — do not process refund without a valid attestation
  const verification = await client.verify(attestation);
  if (!verification.valid) {
    throw new Error(`Attestation verification failed for refund ${refundId}`);
  }

  return {
    refundId,
    approved:
      attestation.execution_state === "completed" &&
      attestation.decision.action === "approve",
    pendingSupervisor:
      attestation.execution_state === "pending_override",
    action: attestation.decision.action,
    reason: attestation.decision.reason,
    attestationSignature: attestation.signature,
  };
}

async function supervisorApproveRefund(
  refundId: string,
  supervisorId: string,
  reason: string
) {
  return client._request<{
    status: string;
    overrideId: string;
  }>("/override", {
    method: "POST",
    body: JSON.stringify({
      executionId: refundId,
      approved: true,
      approvedBy: supervisorId,
      approverRole: "customer_service_supervisor",
      reason,
    }),
  });
}

async function supervisorDenyRefund(
  refundId: string,
  supervisorId: string,
  reason: string
) {
  return client._request<{
    status: string;
    executionId: string;
  }>("/override", {
    method: "POST",
    body: JSON.stringify({
      executionId: refundId,
      approved: false,
      approvedBy: supervisorId,
      approverRole: "customer_service_supervisor",
      reason,
    }),
  });
}

// Example usage
async function main() {
  // Auto-approved
  const small = await requestRefund("REFUND-2024-00881", {
    refundAmount: 35,
    orderAge: 5,
    customerRefundCount: 0,
    refundReason: "wrong_item",
    originalOrderAmount: 35,
    accountStanding: "good",
  });
  console.log(small.action);   // "approve"
  console.log(small.approved); // true

  // Denied: order too old
  const expired = await requestRefund("REFUND-2024-00882", {
    refundAmount: 80,
    orderAge: 120,
    customerRefundCount: 1,
    refundReason: "defective",
    originalOrderAmount: 80,
    accountStanding: "good",
  });
  console.log(expired.action);   // "reject"
  console.log(expired.approved); // false

  // Pending supervisor: high value
  const highValue = await requestRefund("REFUND-2024-00883", {
    refundAmount: 750,
    orderAge: 10,
    customerRefundCount: 1,
    refundReason: "not_as_described",
    originalOrderAmount: 750,
    accountStanding: "good",
  });
  console.log(highValue.action);            // "supervisor_review"
  console.log(highValue.pendingSupervisor); // true

  // Supervisor approves
  if (highValue.pendingSupervisor) {
    const approved = await supervisorApproveRefund(
      "REFUND-2024-00883",
      "supervisor-maria-santos",
      "Customer provided photos. Defect confirmed. Refund approved."
    );
    console.log(approved.status); // "approved"
  }
}

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

***

## Expected results

| Input                           | Expected `action`   | `requires_override` |
| ------------------------------- | ------------------- | ------------------- |
| `refundAmount: 35, orderAge: 5` | `approve`           | `false`             |
| `orderAge: 120`                 | `reject`            | `false`             |
| `accountStanding: "suspended"`  | `reject`            | `false`             |
| `refundAmount: 750`             | `supervisor_review` | `true`              |
| `customerRefundCount: 5`        | `supervisor_review` | `true`              |

***

## Audit trail for finance

```typescript theme={null}
// Pull all refund decisions from a date range
const decisions = await client.audit.decisions({
  policyId: "refund-approval",
  from: "2024-01-01T00:00:00Z",
  to: "2024-01-31T23:59:59Z",
  limit: 1000,
});

const totalApproved = decisions.filter(d => d.decision === "approve").length;
const totalRejected = decisions.filter(d => d.decision === "reject").length;
const pendingReview = decisions.filter(d => d.execution_state === "pending_override").length;

console.log({ totalApproved, totalRejected, pendingReview });
```

***

## Troubleshooting

**Supervisor cannot approve — "Pending override not found"** The execution must have returned `execution_state: "pending_override"`. Verify the `refundId` used in the override request matches the `executionId` used in the execute call exactly (no prefix differences).

**"Override already resolved"** The override was already approved or rejected. Check the audit record:

```typescript theme={null}
const record = await client.audit.decision(refundId);
console.log(record.execution_state); // "completed" or "pending_override"
```

**Agent submitted duplicate refund request** — The second request returns `[INV-013@replay]`. This is correct behavior. Each refund must have a unique `refundId`. Do not retry with the same ID.
