Refunds

    Learn about issuing refunds at Stripe.

    Stripe supports the ability to refund charges made to your account, either in whole or in part. If the original charge underwent currency conversion, the refunded amount is converted back using the same process. There are no fees to refund a charge, but the fees from the original charge are not returned.

    We submit refund requests to your customer’s bank or card issuer immediately. 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 charge via the API, perform a create refund call, providing the ID of the charge to be refunded.

    curl https://api.stripe.com/v1/refunds \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d charge=ch_xsQad4iOWTRLUCPlQL3H
    
    # Set your secret key: remember to change this 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({
        charge: 'ch_xsQad4iOWTRLUCPlQL3H',
    })
    
    # Set your secret key: remember to change this 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(
        charge='ch_xsQad4iOWTRLUCPlQL3H',
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    $refund = \Stripe\Refund::create([
        'charge' => 'ch_xsQad4iOWTRLUCPlQL3H',
    ]);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    Map<String, Object> params = new HashMap<>();
    params.put("charge", "ch_xsQad4iOWTRLUCPlQL3H");
    Refund refund = Refund.create(params);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      const refund = await stripe.refunds.create({
        charge: 'ch_xsQad4iOWTRLUCPlQL3H',
      });
    })();
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    params := &stripe.RefundParams{
        Charge: stripe.String("ch_xsQad4iOWTRLUCPlQL3H"),
    }
    ref, _ := refund.New(params)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    var refundService = new RefundService();
    var refundOptions = new RefundCreateOptions {
      ChargeId = "ch_xsQad4iOWTRLUCPlQL3H",
    };
    Refund refund = refundService.Create(refundOptions);
    

    To refund part of a charge, 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 charge=ch_WzXzWupXtM9AXpHG5uSe \
      -d amount=1000
    
    # Set your secret key: remember to change this 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({
        charge: 'ch_WzXzWupXtM9AXpHG5uSe',
        amount: 1000,
    })
    
    # Set your secret key: remember to change this 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(
        charge='ch_WzXzWupXtM9AXpHG5uSe',
        amount=1000,
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    $refund = \Stripe\Refund::create([
        'charge' => 'ch_WzXzWupXtM9AXpHG5uSe',
        'amount' => 1000,
    ]);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    Map<String, Object> params = new HashMap<>();
    params.put("charge", "ch_WzXzWupXtM9AXpHG5uSe");
    params.put("amount", 1000);
    Refund refund = Refund.create(params);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      const refund = await stripe.refunds.create({
        charge: 'ch_WzXzWupXtM9AXpHG5uSe',
        amount: 1000,
      });
    })();
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    params := &stripe.RefundParams{
        Charge: stripe.String("ch_WzXzWupXtM9AXpHG5uSe"),
        Amount: stripe.Int64(1000),
    }
    ref, _ := refund.New(params)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    var refundOptions = new RefundCreateOptions() {
      ChargeId = "ch_WzXzWupXtM9AXpHG5uSe",
      Amount = 300,
    };
    var refundService = new RefundService();
    Refund refund = refundService.Create(refundOptions);
    

    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 on the charge object. 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/payment_intents/pi_Aabcxyz01aDfoo \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc:
    # Retrieve the ID of the first charge in PaymentIntent
    # charges array returned from the previous request and use
    # it to create a refund.
    curl https://api.stripe.com/v1/refunds \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
    -d charge="{CHARGE_ID}"
    # Set your secret key: remember to change this 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.retrieve('pi_Aabcxyz01aDfoo')
    intent['charges']['data'].first.refund
    
    # Set your secret key: remember to change this 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.retrieve("pi_Aabcxyz01aDfoo")
    intent['charges']['data'][0].refund()
    
    // Set your secret key: remember to change this 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_Aabcxyz01aDfoo");
    $intent->charges->data[0]->refund();
    
    // Set your secret key: remember to change this 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_Aabcxyz01aDfoo");
    String chargeId = intent.getCharges().getData().get(0).getId();
    Refund refund = Refund.create(RefundCreateParams.builder()
      .setCharge(chargeId)
      .build());
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      const intent = await stripe.paymentIntents.retrieve("pi_Aabcxyz01aDfoo");
      const refund = await stripe.refunds.create({
        charge: intent.charges.data[0].id
      });
    })();
    
    // Set your secret key: remember to change this 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.Get("pi_Aabcxyz01aDfoo", nil)
    refundParams := &stripe.RefundParams{
      Charge: stripe.String(intent.Charges.Data[0].ID),
    }
    r, err := refund.New(refundParams)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    var paymentIntents = new PaymentIntentService();
    var refunds = new RefundService();
    var intent = paymentIntents.Get("pi_Aabcxyz01aDfoo");
    var refundOptions = new RefundCreateOptions {
      ChargeId = intent.Charges.Data[0].Id
    };
    var refund = refunds.Create(refundOptions);
    

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

    curl https://api.stripe.com/v1/payment_intents/pi_Aabcxyz01aDfoo \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc:
    # Retrieve the ID of the first charge in PaymentIntent
    # charges array returned from the previous request and use
    # it to create a refund.
    curl https://api.stripe.com/v1/refunds \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
    -d charge="{CHARGE_ID}" \
    -d amount=1000
    # Set your secret key: remember to change this 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.retrieve('pi_Aabcxyz01aDfoo')
    intent['charges']['data'].first.refund(amount: 1000)
    
    # Set your secret key: remember to change this 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.retrieve("pi_Aabcxyz01aDfoo")
    intent['charges']['data'][0].refund(amount=1000)
    
    // Set your secret key: remember to change this 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_Aabcxyz01aDfoo");
    $intent->charges->data[0]->refund(['amount' => 1000]);
    
    // Set your secret key: remember to change this 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_Aabcxyz01aDfoo");
    String chargeId = intent.getCharges().getData().get(0).getId();
    Refund refund = Refund.create(RefundCreateParams.builder()
      .setCharge(chargeId)
      .setAmount(100L)
      .build());
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      const intent = await stripe.paymentIntents.retrieve("pi_Aabcxyz01aDfoo");
      const refund = await stripe.refunds.create({
        charge: intent.charges.data[0].id,
        amount: 1000,
      });
    })();
    
    // Set your secret key: remember to change this 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.Get("pi_Aabcxyz01aDfoo", nil)
    refundParams := &stripe.RefundParams{
      Charge: stripe.String(intent.Charges.Data[0].ID),
      Amount: 1000,
    }
    r, err := refund.New(refundParams)
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    var paymentIntents = new PaymentIntentService();
    var refunds = new RefundService();
    var intent = paymentIntents.Get("pi_Aabcxyz01aDfoo");
    var refundOptions = new RefundCreateOptions {
      ChargeId = intent.Charges.Data[0].Id,
      Amount = 1000
    };
    var refund = refunds.Create(refundOptions);
    

    Using the Dashboard

    To refund a charge via the Dashboard:

    1. Find the charge 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 charge, 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.

    On this page