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

# 5. Ask before a refund

> Pause a tool call for an operator decision and verify the effect.

[Support assistant tutorial](/learn/support-assistant)

This checkpoint uses a simulated refund tool. It changes only a Set in the current process. Run it in an interactive terminal; type `y` to approve or press Enter to deny.

## Complete checkpoint

```typescript support.ts theme={null}
import { createInterface } from "node:readline/promises";
import { stdin, stdout } from "node:process";
import { Agent, defineTool, openai } from "@agentium/core";
import { z } from "zod";

const refunded = new Set<string>();
const refundOrder = defineTool({
  name: "refund_order",
  description: "Record a simulated refund for the demo order ORD-1042. No money moves.",
  parameters: z.object({ orderId: z.literal("ORD-1042") }),
  requiresApproval: true,
  execute: async ({ orderId }) => {
    if (refunded.has(orderId)) return "This demo order was already refunded.";
    refunded.add(orderId);
    return JSON.stringify({ orderId, status: "simulated_refund", moneyMoved: false });
  },
});
const terminal = createInterface({ input: stdin, output: stdout });
const agent = new Agent({
  name: "support",
  model: openai(process.env.OPENAI_MODEL ?? "gpt-6.1-sol"),
  instructions: "Use refund_order when asked to refund the demo order. Explain the actual tool outcome.",
  tools: [refundOrder],
  maxToolRoundtrips: 2,
  approval: {
    policy: ["refund_order"],
    timeout: 60_000,
    onApproval: async ({ toolName, args }) => {
      const answer = await terminal.question(`Allow ${toolName} ${JSON.stringify(args)}? [y/N] `);
      return { approved: answer.trim().toLowerCase() === "y", reason: "Local operator decision" };
    },
  },
});

try {
  const result = await agent.run("Please refund ORD-1042.");
  console.log(result.status, result.text);
  console.log("Simulated refunds:", refunded.size);
} finally {
  terminal.close();
  await agent.close();
}
```

## Run it

```bash theme={null}
npx tsx support.ts
```

## Verify the result

When the model requests the tool, the terminal displays the proposed arguments. Approving should yield `Simulated refunds: 1`; denying should leave the count at `0`. Inspect this state, not just the model's prose.

The default timeout action is denial. A callback that is still awaiting terminal input can remain pending after the SDK's decision; the `finally` block closes the terminal when the run ends.

The Set prevents duplicate demo writes only within this process. A real refund needs provider idempotency, an authoritative eligibility check, a scoped approver, and reconciliation if the provider's outcome is uncertain. See [approval](/agents/approval), [execution policy](/agents/execution-policy), and [recovery](/ship/recovery).

**Try both outcomes** in separate runs. A denied tool call can still produce a successfully completed conversational response explaining the denial.

<Card title="Stream the result" icon="arrow-right" href="/learn/streaming">Continue to the next chapter.</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.