Skip to content
Back to Monetization & Revenue

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.