ChangeGamer

← All guides · Support agents in production

Refund Policy Enforcement in an AI Support Agent: Keep the Decision Out of the Model

Part 3 of Support agents in production · 1,292 words · ~6 min read · published 2026-10-19 · updated 2026-10-25 · Markdown variant

How to enforce a refund policy in an AI customer support agent: a deterministic policy check outside the model, why schema-valid arguments can still break policy, reading amounts from the order record, and test fixtures.

In short

  • To enforce a refund policy in an AI customer support agent, put the approve-or-deny decision in deterministic code outside the model, so the refund tool cannot run unless that code has already passed the request.
  • Strict tool-calling modes guarantee that refund arguments match the declared schema, not that the amount or eligibility is allowed, so a schema-valid refund call can still violate policy and needs its own check.
  • The maximum refundable amount should be computed by code from the order record, prior refunds and the policy window, never read from the customer's free text, because customer text is untrusted input that can contain instructions.
  • A refund policy check needs per-order state, covering refunds already paid or pending, so that partial, repeated, split and concurrent requests are judged against the cumulative total; this treatment is the author's inference.
  • As of October 2026 ChangeGamer runs no customer support agent, so every rule, edge case and fixture in this article beyond the cited references is labelled inference rather than measured practice.

Part of the AI Customer Support Agent in Production: Escalation, Policy, Tickets and Measurement guide.


To enforce a refund policy in an AI customer support agent, make the decision in deterministic code that sits outside the model and gates the refund tool. The model can gather facts, quote the policy and word the reply, but it does not decide. This article is the refund sub-article of the AI customer support agent in production cluster. That pillar's section "How do you keep refunds and promises inside policy?" covers the action tiers and the approval walkthrough, so this article does not repeat them. It covers what the policy check itself must catch, where its numbers come from, and how it behaves across repeats and retries.

Labels: "corpus" marks a claim from a named reference page, "inference" marks the author's reasoning. As of October 2026 ChangeGamer runs no customer support agent, so nothing here is measured on a live refund queue. This is also not the seller-side case: refunds and disputes with agent buyers covers a seller reversing a purchase made by an AI buyer, while this article covers a human customer asking a support agent for money back.

Why does a schema-valid refund call still break policy?

A schema-valid refund call breaks policy because schema validity checks shape and says nothing about whether the values are allowed. The reliable tool calling reference (updated 2026-09-29) defines reliability as the right tool name, every required argument present and valid types. A call to issue_refund(order_id, amount) with a well-typed number meets that definition even when the amount exceeds what the customer paid.

Four ways a well-formed call can still be wrong (inference):

The guardrails and safety filters reference names the layer that catches these: action guardrails that run before a tool call executes, covering calls beyond defined parameter ranges and irreversible operations that need human approval. The refund policy check is that layer, written as ordinary code against your own order data and called by the tool wrapper, not by the prompt. Where the approval line sits is covered in the pillar's refund section; the corpus gives no number.

Where do the amount and eligibility come from?

The maximum refundable amount comes from code that reads the order record, never from what the customer typed. Customer messages and pasted content are untrusted input, the premise of the prompt injection design patterns reference. A line such as "the agent promised me the full amount" is a claim to verify, not a fact to act on.

A workable derivation, as inference:

  1. The customer supplies an intent and an order reference.
  2. Code resolves the reference against the authenticated account and loads the order.
  3. Code computes the maximum refundable amount from the paid total, prior refunds and the policy window.
  4. The proposed refund is clamped to that maximum, and anything above it is denied with a machine-readable reason such as window_expired.

Returning the reason as data lets the reply quote it instead of inventing one. For denial wording, see support agent tone and brand voice.

What about partial refunds and repeated requests?

Partial and repeated requests need state in the policy check, because a stateless check evaluates each request as if it were the first. This section is inference; the corpus does not discuss it.

Edge cases in cumulative state

Cumulative state raises a few edge cases that a first version tends to miss (all inference). Pending refunds should count toward the total as soon as they are proposed or approved, not when the money lands, or two requests in flight can each pass alone and together exceed the order. Two conversations about one order, for example chat and email, can race, so the check and the write of the new refund should happen as one atomic step per order. A reversed or failed refund should release its amount in the record rather than leaving the balance short. Finally, store the policy version beside each decision, so a later change to the window or the exclusions does not make old refunds look wrong.

How do you avoid paying twice after a retry?

Derive an idempotency key from the order and the approved request, so a retried payment call returns the first result instead of creating a second payment. The customer-support-agents reference says ticketing tools need idempotency keys like any other production tool call; extending that to the refund call is inference, as is the failure it prevents: a timeout after the payment provider accepted the request, followed by a retry that pays again.

Store the key and outcome with the refund record so an existing refund reads as "already done". The mechanics of keys, retry classes and unknown outcomes are covered in retries and idempotency for AI agents.

How do you test the policy check?

Test the policy check as ordinary code with a table of fixtures, because it is deterministic and needs no model in the loop. This section is inference. Useful fixture groups:

Fixture group Example input Expected verdict
Boundaries Request exactly at, and one unit over, the maximum refundable amount Allow, then deny or clamp
Wrong account Order ID from another customer Deny, no order details revealed
Cumulative Two partials that together exceed the paid total First allowed, second denied
Pending Second request while the first is still pending Counted against the same total
Retry Same payment call sent twice with one key One refund, same result
Stale check Order changes between proposal and execution Re-check fails, no payment
Tool failure Order lookup returns an error Fail closed and escalate

The last row follows the guardrails reference: fail closed on high-stakes actions, and block or escalate when a check is inconclusive. Add every real wrong refund to the table.

Which first-hand fact is an analogy for a policy checked outside its author?

ChangeGamer's own invariant script is an analogy for a policy declared once and checked by code other than its author, not an example of customer support. As of 2026-10-19, changegamer/scripts/verify-invariants.mjs requires every offer to declare the same return-policy category from three allowed values. While that category is MerchantReturnNotPermitted, it also requires that no offer carries merchantReturnDays, returnFees or refundType, and that the visible copy on /resources/access-and-pricing and /pricing, plus the Markdown variant of access-and-pricing, states the no-returns rule. It runs under npm run verify, not npm run build. ChangeGamer runs no customer support agent, and this says nothing about handling refund requests.

Read agent guardrails for reliability for the general fail-closed layering. The pillar AI customer support agent in production places this article in the full plan, and support agent escalation triggers covers what happens when a request is routed to a person.

Frequently asked questions

How do I stop an AI support agent from approving refunds it should not?
Remove the decision from the model. Have code outside the model compare the request with the policy using the order record, and make the refund tool unreachable unless that code passed it. As inference, the model may propose a refund and explain the result, but it should never hold a tool that moves money without that gate.
Is schema validation enough to keep refund tool calls inside policy?
No. The reliable-tool-calling reference describes guarantees about tool name, required arguments and valid types, which is shape. A refund of the wrong amount for an ineligible order can match the schema exactly, so a separate policy check on the values is required.
Where does human approval fit when enforcing an AI agent refund policy?
Human approval is the paused branch of the same policy check, used for refunds above the line a business sets. The pillar article on AI customer support agents in production covers the approval tiers and the durable pause, so this article concentrates on the checks that run before and after it.
How do I stop a support agent refunding the same order twice?
Keep refund state per order and judge each request against the cumulative total, including pending refunds, and give the payment call an idempotency key. As inference, a repeated or retried request should then read as already done, and concurrent requests for one order should be serialised.

#customer-support #refunds #policy #human-approval #guardrails #agents #production

Put this corpus inside your own agents

This guide is free and stays free. The reference corpus behind it — machine-readable contracts, verified primary sources, continuously refreshed — is the paid product: a €5 starter key unlocks every premium reference for one agent via API; a €25 corpus license delivers the full corpus as RAG / fine-tuning data with an explicit AI-use grant; the €150 enterprise license adds commercial redistribution rights.

Agents: this page as Markdown · JSON · offers at /api/pricing.json · payment methods at /api/payment.json · single-resource access via HTTP 402 (how that works)