GuidesGating Stripe refunds

Gating Stripe refunds

Refunds are the textbook case: cheap to automate, expensive to get wrong. Here we let small refunds through automatically, send medium ones to a human, and block the absurd ones — all from one check() and three policies.

Install and construct

import Stripe from "stripe";
import { Eda } from "@eda-holding-inc/sdk";
 
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const eda = new Eda({ apiKey: process.env.EDA_API_KEY! });

Gate the refund

refund.ts
export async function refundCharge(chargeId: string, amount: number, customerId: string) {
  const decision = await eda.check({
    agent: "support-agent",
    action: "refund_customer",
    params: { amount, customerId, chargeId },
  });
 
  if (decision.status === "pending") {
    // a human needs to approve — see the human-approval guide to wait or defer
    return { status: "awaiting_approval", actionId: decision.actionId };
  }
  if (decision.status !== "approved") {
    return { status: "blocked", reason: decision.reason };
  }
 
  const refund = await stripe.refunds.create({ charge: chargeId, amount });
  return { status: "refunded", refund };
}

Add the tiered policies

In the dashboard → Policies:

PriorityActionConditionEffect
300refund_customeramount > 5000 (i.e. > $50.00 in cents? use your unit)block
200refund_customeramount > 500require_approval
100refund_customerallow
⚠️

Pick a consistent unit for amount (dollars or cents) and use it everywhere — in the params you send and in the policy conditions. Mixing them is the most common bug in refund gating.

Test it from the CLI first

Before shipping code, prove the policies behave:

eda check support-agent refund_customer '{"amount": 300}'   # → approved
eda check support-agent refund_customer '{"amount": 900}'   # → pending
eda check support-agent refund_customer '{"amount": 9000}'  # → blocked

Optional: block refunds to flagged customers

Add a higher-priority policy with a condition on your own signal — pass it in params so Eda can see it:

await eda.check({
  agent: "support-agent",
  action: "refund_customer",
  params: { amount, customerId, chargeId, customerFlagged: await isFlagged(customerId) },
});

Policy: refund_customer where customerFlagged == truerequire_approval (priority above the allow). Now flagged customers always route to a human, regardless of amount.

What you get

Every refund attempt — approved, paused, or blocked — is now in your audit log with the amount, customer, the policy that fired, and (for approvals) who signed off.