6 min read

How to Calculate Refund Rate in Stripe

Refund rate tells you what percentage of money you've charged is coming back. In Stripe, this requires pulling data from two places: your charges and their refunded amounts. This matters because spikes in refund rate signal product issues, customer dissatisfaction, or fraud patterns.

Calculate Refund Rate by Dollar Amount

The most common approach: divide total refunded dollars by total charged dollars.

Fetch all charges for a date range

Use the Charges list endpoint to pull successful charges. Filter by creation date to define your period. Stripe paginates results at 100 per page, so loop through all pages to get the complete dataset.

javascript
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

const startDate = Math.floor(new Date('2026-01-01').getTime() / 1000);
const endDate = Math.floor(new Date('2026-03-26').getTime() / 1000);

let allCharges = [];
let hasMore = true;
let startingAfter = null;

while (hasMore) {
  const charges = await stripe.charges.list({
    created: { gte: startDate, lte: endDate },
    limit: 100,
    starting_after: startingAfter
  });
  
  allCharges = allCharges.concat(charges.data);
  hasMore = charges.has_more;
  if (charges.data.length > 0) {
    startingAfter = charges.data[charges.data.length - 1].id;
  }
}
Paginate through all charges in your date range using the Stripe Node.js SDK

Sum total charge amounts

Add up all amount fields from the charges array. Stripe stores amounts in cents, so $10 appears as 1000. Keep totals in cents during calculation.

javascript
const totalCharged = allCharges.reduce((sum, charge) => {
  return sum + charge.amount;
}, 0);

console.log(`Total charged: $${(totalCharged / 100).toFixed(2)}`);

Sum total refunded amounts

Each charge has an amount_refunded field that tracks the total refunded (including partial refunds). Loop through and sum these values.

javascript
const totalRefunded = allCharges.reduce((sum, charge) => {
  return sum + charge.amount_refunded;
}, 0);

console.log(`Total refunded: $${(totalRefunded / 100).toFixed(2)}`);

Calculate the refund rate percentage

Divide total refunded by total charged and multiply by 100. This is your refund rate as a percentage.

javascript
const refundRate = totalCharged > 0 ? (totalRefunded / totalCharged) * 100 : 0;
console.log(`Refund rate: ${refundRate.toFixed(2)}%`);
Tip: The amount_refunded field already includes partial refunds, so you don't need to separately query the Refunds API for this calculation.

Calculate Refund Rate by Transaction Count

Count how many transactions had any refund, divided by total transactions. This metric answers: "What percentage of my customers initiated a refund?"

Count transactions with refunds

Filter charges where amount_refunded > 0. Any charge with a refund amount greater than zero counts, whether it's partial or full.

javascript
const chargesWithRefunds = allCharges.filter(charge => charge.amount_refunded > 0);
const refundedTransactionCount = chargesWithRefunds.length;
const totalChargeCount = allCharges.length;

console.log(`Refunded transactions: ${refundedTransactionCount} of ${totalChargeCount}`);

Calculate transaction refund rate

Divide refunded transaction count by total transaction count and multiply by 100.

javascript
const refundRateByCount = totalChargeCount > 0 ? (refundedTransactionCount / totalChargeCount) * 100 : 0;
console.log(`Transaction refund rate: ${refundRateByCount.toFixed(2)}%`);
Watch out: Dollar-based and transaction-based refund rates diverge when refund sizes vary. A few large refunds impact dollar rate more than transaction rate. Use both metrics to understand the full picture.

Track Refund Rate Trends Over Time

Store daily refund rate calculations so you can spot trends and correlate changes with product releases or policy changes.

Set up daily refund rate logging

Create a scheduled function (Lambda, cron job, or Cloud Task) that calculates and stores the refund rate every day. Include the dollar amounts so you can break down the metric later.

javascript
const calculateDailyRefundRate = async () => {
  const now = Math.floor(Date.now() / 1000);
  const oneDayAgo = now - (24 * 60 * 60);
  
  const charges = await stripe.charges.list({
    created: { gte: oneDayAgo, lte: now },
    limit: 100
  });
  
  const totalCharged = charges.data.reduce((s, c) => s + c.amount, 0);
  const totalRefunded = charges.data.reduce((s, c) => s + c.amount_refunded, 0);
  const refundRate = totalCharged > 0 ? (totalRefunded / totalCharged) * 100 : 0;
  
  // Store in your database or data warehouse
  await analytics.store({
    date: new Date().toISOString().split('T')[0],
    refund_rate: refundRate,
    total_charged: totalCharged,
    total_refunded: totalRefunded,
    transaction_count: charges.data.length
  });
};

Common Pitfalls

  • Forgetting pagination: Stripe defaults to 100 results per request. Without looping through has_more, you'll miss charges and calculate a wrong rate.
  • Including test mode charges: Your test charges can inflate numbers. Always verify you're querying with the correct live API key before running production reports.
  • Not filtering by charge status: Charges with status: 'failed' shouldn't count. Filter for status: 'succeeded' to only include settled charges.
  • Confusing refunds with disputes: A disputed charge and a refund are different in Stripe. Disputes go through a resolution process; refunds are money you're giving back. Only count amount_refunded for true refund rate.

Wrapping Up

You can calculate refund rate two ways in Stripe: by dollar amount (tracks revenue impact) or by transaction count (tracks customer friction). Dollar-based is more common for financial reporting. Set up daily tracking in a database to catch refund spikes early and correlate them with product changes. If you want to connect refund rate to churn, feature adoption, or cohort behavior across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free