Learn how to refund a payment in Stripe using the Dashboard or API (Node.js, PHP, Python, cURL), monitor refund status, handle errors, and follow best practices.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Refund a Payment in Stripe
Stripe provides a straightforward way to process refunds for payments. This comprehensive tutorial will walk you through different methods of refunding payments in Stripe, covering both the Dashboard interface and API implementations.
Step 1: Understanding Stripe Refunds
Before diving into the refund process, it's important to understand how refunds work in Stripe:
Step 2: Refunding a Payment Using the Stripe Dashboard
The simplest way to process a refund is through the Stripe Dashboard:
Step 3: Refunding a Payment Using the Stripe API with Node.js
For programmatic refunds, you can use Stripe's API. Here's how to implement it with Node.js:
const stripe = require('stripe')('sk_test_your_secret_key');
async function refundPayment(chargeId, amount = null, reason = null) {
try {
const refundParams = {
charge: chargeId,
// Optional parameters
...(amount && { amount: amount }), // For partial refunds (in cents)
...(reason && { reason: reason }), // Possible values: 'duplicate', 'fraudulent', 'requested_by_customer'
};
const refund = await stripe.refunds.create(refundParams);
console.log('Refund processed successfully:', refund);
return refund;
} catch (error) {
console.error('Error processing refund:', error);
throw error;
}
}
// Example usage:
// Full refund
refundPayment('ch\_1234567890');
// Partial refund ($10.00)
refundPayment('ch\_1234567890', 1000);
// Refund with reason
refundPayment('ch_1234567890', null, 'requested_by\_customer');
Step 4: Refunding a Payment Using the Stripe API with PHP
If you're using PHP, here's how to implement refunds:
// Include Stripe PHP SDK
require\_once 'vendor/autoload.php';
// Set your secret key
\Stripe\Stripe::setApiKey('sk_test_your_secret_key');
function refundPayment($chargeId, $amount = null, $reason = null) {
try {
$refundParams = [
'charge' => $chargeId,
];
// Add optional parameters if provided
if ($amount !== null) {
$refundParams['amount'] = $amount; // For partial refunds (in cents)
}
if ($reason !== null) {
$refundParams['reason'] = $reason; // 'duplicate', 'fraudulent', 'requested_by_customer'
}
$refund = \Stripe\Refund::create($refundParams);
echo "Refund processed successfully: " . $refund->id;
return $refund;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo "Error processing refund: " . $e->getMessage();
throw $e;
}
}
// Example usage:
// Full refund
refundPayment('ch\_1234567890');
// Partial refund ($15.50)
refundPayment('ch\_1234567890', 1550);
Step 5: Refunding a Payment Using the Stripe API with Python
For Python developers, here's how to implement refunds:
import stripe
# Set your secret key
stripe.api_key = 'sk_test_your_secret\_key'
def refund_payment(charge_id, amount=None, reason=None):
try:
refund\_params = {
'charge': charge\_id,
}
# Add optional parameters if provided
if amount is not None:
refund\_params['amount'] = amount # For partial refunds (in cents)
if reason is not None:
refund_params['reason'] = reason # 'duplicate', 'fraudulent', 'requested_by\_customer'
refund = stripe.Refund.create(\*\*refund\_params)
print(f"Refund processed successfully: {refund.id}")
return refund
except stripe.error.StripeError as e:
print(f"Error processing refund: {e}")
raise e
# Example usage:
# Full refund
refund_payment('ch_1234567890')
# Partial refund ($25.00)
refund_payment('ch_1234567890', 2500)
# Refund with reason
refund_payment('ch_1234567890', reason='requested_by_customer')
Step 6: Refunding a Payment Using cURL
If you prefer using cURL for API requests:
curl https://api.stripe.com/v1/refunds \\
-u sk_test_your_secret_key: \\
-d charge=ch\_1234567890 \\
-d amount=1000 \\
-d reason=requested_by_customer
Step 7: Handling Refund Webhooks
To keep your system in sync with refund statuses, set up webhooks to listen for refund events:
// Node.js example with Express
const express = require('express');
const stripe = require('stripe')('sk_test_your_secret_key');
const app = express();
// Use JSON parser for webhook requests
app.use('/webhook', express.raw({type: 'application/json'}));
app.post('/webhook', async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
'whsec_your_webhook_signing_secret'
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
switch (event.type) {
case 'charge.refunded':
const chargeRefunded = event.data.object;
console.log('Charge refunded:', chargeRefunded.id);
// Update your database or notify your users
break;
case 'refund.created':
const refundCreated = event.data.object;
console.log('Refund created:', refundCreated.id);
break;
case 'refund.updated':
const refundUpdated = event.data.object;
console.log('Refund updated:', refundUpdated.id, 'Status:', refundUpdated.status);
break;
default:
console.log(`Unhandled event type ${event.type}`);
}
// Return a 200 response to acknowledge receipt of the event
res.send();
});
app.listen(3000, () => {
console.log('Webhook listener running on port 3000');
});
Step 8: Monitoring Refund Status
Refunds can have various statuses that you should monitor:
You can check a refund's status using the API:
// Node.js example
async function checkRefundStatus(refundId) {
try {
const refund = await stripe.refunds.retrieve(refundId);
console.log(`Refund ${refundId} status: ${refund.status}`);
return refund;
} catch (error) {
console.error('Error checking refund status:', error);
throw error;
}
}
// Example usage
checkRefundStatus('re\_1234567890');
Step 9: Handling Failed Refunds
Sometimes refunds can fail. Here's how to handle failed refunds:
// Node.js example
async function handleFailedRefund(refundId) {
try {
const refund = await stripe.refunds.retrieve(refundId);
if (refund.status === 'failed') {
console.log(`Refund ${refundId} failed. Reason: ${refund.failure_reason}`);
// Common failure reasons:
// - expired_or_canceled\_card
// - lost_or_stolen\_card
// - unknown
// You might want to:
// 1. Notify the customer
// 2. Try an alternative refund method
// 3. Provide manual support
return {
success: false,
reason: refund.failure\_reason,
refund: refund
};
}
return { success: true, refund: refund };
} catch (error) {
console.error('Error handling failed refund:', error);
throw error;
}
}
Step 10: Best Practices for Refunds
Follow these best practices when implementing refunds:
Conclusion
Refunding payments in Stripe can be done through the Dashboard for manual processing or via the API for automated solutions. Whether you're using Node.js, PHP, Python, or direct API calls, Stripe provides flexible options to handle refunds according to your business needs. Remember to properly monitor refund statuses and implement appropriate error handling to ensure a smooth refund experience for your customers.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.