Refund Process
How to process refunds consistently with a policy, approval workflow, and customer communication that prevents chargebacks.
Why
Refunds are inevitable — some customers will be unhappy, some will have bought by mistake, and some will have churned mid-cycle. The question is not whether to refund but how to process them consistently: a clear policy (when you refund, how much, within what window), an approval workflow (who can approve a $29 refund vs a $500 refund), and customer communication (tell them when the refund is processed and when to expect it on their card). The alternative is ad-hoc refunds: the support team refunds some customers fully and others partially, there is no record of why, and the finance team cannot reconcile. Worse, without a clear refund path, customers dispute the charge with their bank (chargeback), which costs you a $15 chargeback fee plus the refund amount plus lost product time. A good refund process costs you the refund amount but saves the chargeback fee, the support time, and the customer relationship (a customer who gets a smooth refund may come back; a customer who has to chargeback never does). The most common mistake is making refunds hard (requiring 3 emails and a manager) — this pushes customers to chargeback, which is 5x more expensive.
When
Whenever a customer requests a refund. Have the policy and workflow set up before the first request, so the team knows what to do.
How
1. Define a refund policy: full refund within 14 days of purchase (no questions asked), pro-rated refund within 30 days, no refund after 30 days (unless there was a service outage) 2. Publish the policy on /refund-policy — this sets customer expectations and gives the support team a reference point 3. Set an approval workflow: support agents can refund up to $50, team leads up to $200, managers up to $500, anything above requires a director — this prevents fraud and large surprise refunds 4. Process the refund in Stripe: use stripe.refunds.create with the charge ID and an optional reason (for your records) — Stripe refunds to the original payment method 5. Communicate with the customer: 'I have processed your refund of $29. It will appear on your card within 5-10 business days. You will receive a confirmation email from Stripe.' — set expectations on timing 6. Log the refund reason in your support system: 'requested refund — product did not fit needs' — this data helps you identify product issues and reduce future refunds 7. For partial refunds (pro-rated for days used), explain the math: 'you used 10 days of a 30-day cycle, so the refund is $29 × (20/30) = $19.33' — transparency prevents 'why did I only get $19' tickets 8. Track refund rate by cohort and reason — if refunds spike after a new release, the release introduced a regression; if refunds cluster on a specific plan, the plan's pricing or features are misaligned
Example
# Refund policy (published on /refund-policy)
# - Within 14 days: full refund, no questions asked
# - Within 30 days: pro-rated refund (days unused / total days × amount)
# - After 30 days: no refund (unless service outage)
# - Chargebacks: we will refund directly, please contact support first
# Approval workflow
const APPROVAL_LIMITS = { agent: 50, lead: 200, manager: 500, director: Infinity };
async function processRefund(chargeId: string, amount: number, agent: Agent) {
if (amount > APPROVAL_LIMITS[agent.role]) {
throw new Error(`Refund of $${amount} requires ${nextRole(agent.role)} approval`);
}
const refund = await stripe.refunds.create({
charge: chargeId,
amount: amount * 100, // cents
reason: "requested_by_customer",
metadata: { agent: agent.id, reason: agent.refundReason },
});
await emailCustomer(refund, "Your refund of $X will appear in 5-10 business days.");
return refund;
}
# Partial refund (pro-rated)
// Customer on $29/mo plan, requests refund on day 10
// Used: 10 days, Unused: 20 days
// Refund: $29 × (20/30) = $19.33
// Explain: "you used 10 of 30 days, so the refund is $19.33 (20/30 × $29)"Common Problems
- ⚠Making refunds hard (3 emails + manager approval for $29) — customers give up and chargeback, which costs $15 + the refund + lost relationship. Make small refunds easy for support agents.
- ⚠No published refund policy — customers do not know what to expect, so they chargeback instead of asking. Publish a clear policy on /refund-policy.
- ⚠Not communicating refund timing — the customer expects the refund in 2 days, it takes 5-10 business days, and they chargeback in the meantime. Tell them the timing upfront.
Best Practices
- ✓Publish a clear refund policy (14-day full, 30-day pro-rated) and let support agents refund up to $50 without approval — this makes small refunds easy and prevents chargebacks.
- ✓Communicate refund timing (5-10 business days) in the first response — this sets expectations and prevents the customer from charging back while waiting.
- ✓Track refund rate and reason by cohort — spikes after a release indicate a regression, and clusters on a plan indicate a pricing or feature mismatch.