Auto-approve refunds safely
Approve refunds automatically only when the request clearly meets the policy, decline the clear no's, and send everything in between to a person. Because the probabilities are calibrated, the thresholds translate directly into an error rate.
from simoai import Client, Fill, Noul
c = Client()
POLICY = """Refunds are allowed within 30 days of delivery for items that arrived damaged or not as described.
Opened software and gift cards are not refundable. Refunds over $500 need a manager."""
def decide(ticket: str, order: dict) -> str:
r = c.ask(
{"policy": POLICY, "order": order, "ticket": ticket},
{
"eligible": Noul("The refund request meets the policy"),
"amount": Fill("the amount the customer wants refunded, in dollars", kind="number"),
"fraud": Noul("The request shows signs of fraud or abuse"),
},
two_pass=True, # read the amount first, then decide with it in view
)
p, amount = r["eligible"].noul, r["amount"].parsed
if r["fraud"].noul > 0.3:
return "review: possible abuse"
if amount is not None and amount > 500:
return "review: needs a manager"
if p > 0.97:
return f"approve ${amount}"
if p < 0.05:
return "decline"
return f"review: eligible p={p:.2f}"
print(decide("The blender arrived with a cracked jug. I'd like my money back.",
{"item": "Blender", "price": 89, "delivered": "2026-10-09", "today": "2026-10-18"}))
# approve $89.0const POLICY = `Refunds are allowed within 30 days of delivery for items that arrived damaged or not as described.
Opened software and gift cards are not refundable. Refunds over $500 need a manager.`;
async function decide(ticket, order) {
const res = await fetch("https://api.temprl.org/v1/ask", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SIMO_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
model: "simo-1-pro",
state: { policy: POLICY, order, ticket },
questions: {
eligible: { type: "noul", instructions: "The refund request meets the policy" },
amount: { type: "fill", instructions: "the amount the customer wants refunded, in dollars", kind: "number", max_tokens: 16 },
fraud: { type: "noul", instructions: "The request shows signs of fraud or abuse" },
},
options: { two_pass: 1 },
}),
});
const { answers: a } = await res.json();
if (a.fraud.noul > 0.3) return "review: possible abuse";
if (a.amount.parsed > 500) return "review: needs a manager";
if (a.eligible.noul > 0.97) return `approve $${a.amount.parsed}`;
if (a.eligible.noul < 0.05) return "decline";
return `review: eligible p=${a.eligible.noul.toFixed(2)}`;
}Choosing the thresholds
Set each threshold from what a mistake costs, and let the calibration tell you the trade-off:
| Threshold to approve | Wrong approvals among those approved near the threshold | Share sent to people |
|---|---|---|
| 0.90 | about 1 in 10 | lower |
| 0.97 | about 3 in 100 | medium |
| 0.99 | about 1 in 100 | higher |
Log every decision with its probability, then check a sample: approvals made at 0.97 should be right about 97% of the time. The business rules (manager over $500, the fraud flag) stay in your code, where they are exact.