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.
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;
}
}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.
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.
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.
const refundRate = totalCharged > 0 ? (totalRefunded / totalCharged) * 100 : 0;
console.log(`Refund rate: ${refundRate.toFixed(2)}%`);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.
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.
const refundRateByCount = totalChargeCount > 0 ? (refundedTransactionCount / totalChargeCount) * 100 : 0;
console.log(`Transaction refund rate: ${refundRateByCount.toFixed(2)}%`);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.
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 forstatus: '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_refundedfor 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.