Payments
After the payment
Refunds

Refunding and canceling payments

Learn how to refund or cancel a payment.

You can refund charges made to your account, either in whole or in part. Refunds use your available Stripe balance—this doesn’t include any pending balance. If your available balance doesn’t cover the amount of the refund, Stripe debits the remaining amount from your bank account.

​​If Stripe can’t debit the remaining amount from your bank account, your refunds may go into a pending status until you add funds to your Stripe balance. You can view a list of all your pending refunds in the Dashboard.

If the original charge underwent currency conversion, the refunded amount converts back using the same process. There are no fees to refund a charge, but the fees from the original charge aren’t returned.

We submit refund requests to your customer’s bank or card issuer. Your customer sees the refund as a credit approximately 5-10 business days later, depending upon the bank. Once issued, a refund cannot be canceled. Disputes and chargebacks aren’t possible on credit card charges that are fully refunded.

We’ll also send an email to your customer notifying them of the refund, if all of these conditions apply:

  • The original charge was created on a Customer object in your Stripe account
  • The Customer object has a stored email address
  • You have Email customers for refunds enabled

Some refunds—those issued shortly after the original charge—appear in the form of a reversal instead of a refund. In the case of a reversal, the original charge drops off the customer’s statement, and a separate credit is not issued.

Issuing refunds

Refunds can be issued via the API or the Dashboard and are processed immediately. Once issued, a refund cannot be canceled.

You can issue more than one refund against a charge, but you cannot refund a total greater than the original charge amount.

Using the API

To refund a payment via the API, create a Refund and provide the ID of the charge to be refunded.

When you use a PaymentIntent to collect payment from a customer, Stripe creates a charge behind the scenes. To refund the customer’s payment after the PaymentIntent has succeeded, create a refund using the PaymentIntent, which is equivalent to refunding the underlying charge. You can also optionally refund part of their payment by specifying an amount. You can perform refunds with the API or through the Dashboard.

Note that this does not apply if you are using separate authorization and capture, and you wish to refund a PaymentIntent that has a status of requires_capture. In this case, the charge attached to the PaymentIntent is still uncaptured and cannot be refunded directly. You should cancel the PaymentIntent instead.

curl https://api.stripe.com/v1/refunds \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d payment_intent=pi_Aabcxyz01aDfoo
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' refund = Stripe::Refund.create({ payment_intent: 'pi_Aabcxyz01aDfoo', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' refund = stripe.Refund.create( payment_intent='pi_Aabcxyz01aDfoo', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $re = \Stripe\Refund::create([ 'payment_intent' => 'pi_Aabcxyz01aDfoo', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; Refund refund = Refund.create(RefundCreateParams.builder() .setPaymentIntent("pi_Aabcxyz01aDfoo") .build());
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const refund = await stripe.refunds.create({ payment_intent: 'pi_Aabcxyz01aDfoo', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" refundParams := &stripe.RefundParams{ PaymentIntent: "pi_Aabcxyz01aDfoo", } r, err := refund.New(refundParams)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var refunds = new RefundService(); var refundOptions = new RefundCreateOptions { PaymentIntent = "pi_Aabcxyz01aDfoo" }; var refund = refunds.Create(refundOptions);

To refund part of a PaymentIntent, provide an amount parameter, as an integer in cents (or the charge currency’s smallest currency unit):

curl https://api.stripe.com/v1/refunds \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d payment_intent=pi_Aabcxyz01aDfoo \ -d amount=1000
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' refund = Stripe::Refund.create({ amount: 1000, payment_intent: 'pi_Aabcxyz01aDfoo', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' refund = stripe.Refund.create( amount=1000, payment_intent='pi_Aabcxyz01aDfoo', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $re = \Stripe\Refund::create([ 'amount' => 1000, 'payment_intent' => 'pi_Aabcxyz01aDfoo', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; Refund refund = Refund.create(RefundCreateParams.builder() .setAmount(1000L) .setPaymentIntent("pi_Aabcxyz01aDfoo") .build());
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const refund = await stripe.refunds.create({ amount: 1000, payment_intent: 'pi_Aabcxyz01aDfoo', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" refundParams := &stripe.RefundParams{ Amount: 1000, PaymentIntent: "pi_Aabcxyz01aDfoo", } r, err := refund.New(refundParams)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var refunds = new RefundService(); var refundOptions = new RefundCreateOptions { PaymentIntent = "pi_Aabcxyz01aDfoo", Amount = 1000 }; var refund = refunds.Create(refundOptions);

Canceling a PaymentIntent

You can cancel a PaymentIntent if you no longer intend to use it to collect payment from the customer. Canceling a PaymentIntent is optional, and it’s okay to keep a PaymentIntent in an incomplete status like requires_confirmation or requires_payment_method. Incomplete PaymentIntents are useful in understanding the conversion rate at checkout.

curl https://api.stripe.com/v1/payment_intents/pi_4rQu2rzBhEkimVHZZxZM/cancel \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -X POST
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.cancel('pi_4rQu2rzBhEkimVHZZxZM')
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.cancel('pi_4rQu2rzBhEkimVHZZxZM')
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::retrieve('pi_4rQu2rzBhEkimVHZZxZM'); $intent->cancel();
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentIntent intent = PaymentIntent.retrieve("pi_4rQu2rzBhEkimVHZZxZM"); intent.cancel();
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); await stripe.paymentIntents.cancel('pi_4rQu2rzBhEkimVHZZxZM');
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" intent, err := paymentintent.Cancel("pi_4rQu2rzBhEkimVHZZxZM", nil)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new PaymentIntentService(); var options = new PaymentIntentCancelOptions{}; var intent = service.Cancel("pi_4rQu2rzBhEkimVHZZxZM", options);

A PaymentIntent can only be canceled when it has one of the following statuses: requires_payment_method, requires_capture, requires_confirmation, or requires_action—a PaymentIntent can’t be canceled while it is actively processing or once it has succeeded.

When a PaymentIntent is canceled, you can no longer use it to perform additional charges. Any operations that your application attempts to perform on a canceled PaymentIntent will fail with an error.

Using the Dashboard

To refund a payment via the Dashboard:

  1. Find the payment to be refunded in the payments overview page.
  2. Click the ••• icon to the right of the charge. From the resulting menu, select Refund payment.
  3. By default, you will issue a full refund. For a partial refund, enter a different amount to be refunded.
  4. Select a reason for the refund. If you select Other, you must provide an explanatory note that is attached to the refund.
  5. Click Refund.

Alternatively, you can go to the Dashboard page for the specific payment, and click Refund there. (Again, you’ll be given the choice of a full or partial refund and prompted to pick a reason.)

Refund destinations

Refunds can be sent back only to the original payment method used in a charge. It’s not possible to send a refund to a different destination (e.g., another card or bank account).

Refunds to expired or canceled cards are handled by the customer’s card issuer and, in most cases, credited to the customer’s replacement card. If no replacement exists, the card issuer usually delivers the refund to the customer using an alternate method (e.g., check or bank account deposit). In rare cases, a refund back to a card may fail.

For additional payment methods (ACH, iDEAL, etc.), refund handling can vary from bank to bank. If a customer has closed their method of payment, the bank may return the refund to us—at which point it is marked as failed.

Handling failed refunds

A refund can fail if the customer’s bank or card issuer has been unable to process it correctly (e.g., a closed bank account or a problem with the card). The bank returns the refunded amount to us and we add it back to your Stripe account balance. This process can take up to 30 days from the post date.

The Refund object’s status transitions to failed and includes these attributes:

  • failure_reason, the reason why the refund failed
  • failure_balance_transaction, the ID of the balance transaction representing the amount returned to your Stripe balance

In the rare instance that a refund fails, we notify you using the charge.refund.updated webhook event. You will then need to arrange an alternative way of providing your customer with a refund.

Tracing a refund

Once you initiate a refund, Stripe submits refund requests to your customer’s bank or card issuer. Your customer sees the refund as a credit approximately 5-10 business days later, depending upon the bank.

A customer may contact you if they don’t see the refund. A refund may not be visible to the customer for several reasons:

  • Refunds issued shortly after the original charge appear in the form of a reversal instead of a refund. In the case of a reversal, the original charge drops off the customer’s statement, and a separate credit is not issued.
  • Refunds can fail if the customer’s bank or card issuer has been unable to process it correctly. The bank returns the refunded amount to us and we add it back to your Stripe account balance. This process can take up to 30 days from requesting the refund.

If a customer is asking about a refund, it can be helpful to give them the Acquirer Reference Number (ARN) corresponding to the refund. An ARN is a unique number assigned to a card transaction as it moves through the payment flow. Your customer can then take the ARN to their bank, which will be able to provide more information about when the refund will be available. Having a reference number can also increase your customer’s confidence that the refund has been initiated.

ARNs are available under the following conditions:

  • They are only supported for Visa and Mastercard transactions.
  • It takes 1-3 business days after initiating the refund to receive the ARN from downstream banking partners.
  • An ARN is not available in the case of a reversal, since the original charge is not processed.

Where available, Stripe shows the ARN corresponding to a refund in the Dashboard on the payment detail page of the refunded payment.

Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.