Collect taxes for recurring payments
Learn how to collect and report taxes for recurring payments.
To calculate tax for recurring payments, Stripe offers Stripe Tax and Tax Rates.
Stripe Tax—a paid product that automatically calculates the tax on your transactions without the need to define the rates and rules. Fees only apply after you’ve added at least one location where you’re registered to calculate and remit tax. For more information, see Stripe Tax.
Tax Rates—a free feature that allows you to define any number of tax rates for invoices, subscriptions, and one-time payments that use Checkout. Stripe won’t create or maintain any tax rates on your behalf. For more information, see Tax Rates and how to use them.
Stripe Tax allows you to calculate the tax amount on your recurring payments when using Stripe Billing. Use your customer’s location details to preview the tax amount before creating a subscription and then create it with Stripe Tax enabled when your customer is ready to pay. Stripe Tax integrates with Stripe Billing and automatically handles tax calculation with your pricing model, prorations, discounts, trials, and so on.
Customer
Client
Server
Stripe
Go to your checkout page
Enter address information
Estimate taxes and total
POST /v1/invoices/create_
Return a preview invoice
Return taxes and total
Submit
Submit
POST /v1/customers/:id
Return the updated Customer
POST /v1/subscriptions
Return a new subscription
Return client secret
stripe.
Redirect to return_
This guide assumes you’re setting up Stripe Tax and Billing for the first time. See how to update existing subscriptions.
If you’re using Stripe Checkout to create new subscriptions, see how to automatically collect tax on Checkout sessions, or watch the short video below:
Update your products and prices (optional)
Stripe Tax uses information stored on products and prices to calculate tax, such as tax code and tax behavior. If you don’t explicitly specify these configurations, Stripe Tax will use the default tax code selected in Tax Settings.
For more information, see Specify product tax codes and tax behaviour.
Estimate taxes and totalServer-side
Check the automatic_tax.status of the invoice. If the status is requires_
, it means that the address details are invalid or insufficient. In this case, prompt your customer to re-enter their address details or provide accurate address details.
The invoice total is how much your customer pays and tax is the sum of all tax amounts on the invoice. If you want a breakdown of taxes, see total_tax_amounts. All amounts are in cents.
Zero tax
If the tax
is zero, make sure that you have a tax registration in your customer’s location. See how to register for sales tax, VAT, and GST and learn more about zero tax amounts and reverse charges.
Collect customer informationClient-side
After you have an estimate of the taxes and the total, start collecting customer information including their shipping address (if applicable), billing address, and their payment details. Notice that when you use Stripe Tax, you collect payment details without an Intent. The first step is to create an Elements object without an Intent:
const stripe = Stripe(
); const elements = stripe.elements({ mode: 'subscription', currency: '{{CURRENCY}}', amount:"pk_test_TYooMQauvdEDq54NiTphI7jx", });{{TOTAL}}
Next, create an Address Element and a Payment Element and mount both:
const addressElement = elements.create('address', { mode: 'billing' // or 'shipping', if you are shipping goods }); addressElement.mount('#address-element'); const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element');
Then you can listen to change events on the Address Element. When the address changes, re-estimate the taxes and the total.
addressElement.on('change', function(event) { // Throttle your requests to avoid overloading your server or hitting // Stripe's rate limits. const { tax, total } = await updateEstimate(event.value.address); elements.update({ amount: total }); // Update your page to display the new tax and total to the user... });
Common mistake
When your customer is entering their address, Address Element fires a change
event for each keystroke. To avoid overloading your server and hitting Stripe’s rate limits, wait for some time after the last change
event before re-estimating the taxes and the total.
Handle submissionClient-side
When your customer submits the form, call elements.submit() to validate the form fields and collect any data required for wallets. You must wait for this function’s promise to resolve before performing any other operations.
document.querySelector("#form").addEventListener("submit", function(event) { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); const { error: submitError } = await elements.submit(); if (submitError) { // Handle error... return; } const { value: customerDetails } = await addressElement.getValue(); // See the "Save customer details" section below to implement this // server-side. await
(customerDetails); // See the "Create subscription" section below to implement this server-side. const {saveCustomerDetails} = awaitclientSecret(); const { error: confirmError } = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url:createSubscription, }, }); if (confirmError) { // Handle error... return; } // Upon a successful confirmation, your user will be redirected to the // return_url you provide before the Promise ever resolves. });{{RETURN_URL}}
Save customer detailsServer-side
Update your Customer
object using the details you’ve collected from your customer, so that Stripe Tax can determine their precise location for accurate results.
Regional considerationsUnited States
If your customer is in the United States, provide a full address if possible. We use the term “rooftop-accurate” to mean that we can attribute your customer’s location to a specific house or building. This provides greater accuracy, where two houses located side-by-side on the same street might be subject to different tax rates, because of complex jurisdiction boundaries.
If you haven’t already created a Customer
object (for example, when your customer first signs up on your website), you can create one now.
The tax.validate_location enum value helps you make sure that the tax location of the customer becomes (or remains) valid as a result of this operation. If not, Stripe fails your request with the customer_tax_location_invalid error code. This is important because you can’t create an automatic tax enabled subscription for a customer with an invalid tax location. If you’ve been checking the automatic_tax.status of your preview invoices as advised previously, this additional validation won’t ever fail. However, it’s good practice to set tax[validate_
whenever you’re creating or updating a Customer
object.
Create subscriptionServer-side
Create a subscription with automatic tax enabled.
The latest_invoice.payment_intent.client_secret is the client secret of the payment intent of the first (and the latest) invoice of the new subscription. You need to pass the client secret to your front end to be able to confirm the payment intent.
Security tip
Don’t store, log, or expose the client secret to anyone other than the customer. Make sure that you have TLS enabled on any page that includes the client secret.
If your customer has a default payment method, the first invoice of the subscription is paid automatically. You can confirm this using latest_invoice.status of the subscription. If you want to use the new payment details you collected from your customer in your checkout flow, make sure that the first invoice isn’t paid automatically. Pass default_
for the payment_behavior when you’re creating your subscription and confirm the payment intent using stripe.confirmPayment() as shown. See Billing collection methods for more information.
Use webhooks 
We recommend listening to subscription events with webhooks because most subscription activity happens asynchronously.
When you start using Stripe Tax, make sure to listen to invoice.finalization_failed events. If the automatic_tax.status of the invoice is requires_
, it means that the address details of your customer are invalid or insufficient. In this case, Stripe can’t calculate the taxes, can’t finalize the invoice, and can’t collect the payment. Notify your customer to re-enter their address details or provide an accurate address.
See Using webhooks with subscriptions to learn more.
To collect taxes on a subscription, set tax rates on the subscription or set the tax rates on invoices as the subscription cycles. Or, if you use Checkout, you can specify tax rates in Checkout Sessions to apply taxes to subscriptions.
Setting tax rates on a subscription Recommended
You can apply taxes at the subscription level and the subscription item level and set up to five tax rates on each subscription item.
When invoices are generated for subscriptions, tax rates are copied from the subscription to the invoice. In the example below, the first subscription item has two tax rates: 3% and 5%, which overrides the 1% from the subscription level tax rate. The second item doesn’t have any tax rates set directly on it, so the 1% from the subscription level tax rate is automatically applied.
Subscription item 1 | 3% and 5% | ➡️ | Invoice item 1 | 3% and 5% |
Subscription item 2 | (no tax set) | ➡️ | Invoice item 2 | (no tax set) |
Subscription | 1% | ➡️ | Invoice | 1% |
You can set tax rates when you create or update subscription items by passing the tax rate IDs. The example below updates an existing subscription item with two tax rates:
You can set subscription level tax rates when you create or update subscriptions. Set the tax rates you want to apply by passing the default tax rate IDs. The example below updates an existing subscription with two tax rates:
Dynamically configuring tax rates on each subscription cycle 
If you add extra invoice items, or sell in enough jurisdictions that tax rates change frequently, you can dynamically calculate and assign tax rates to the subscription’s invoice as it’s created.
When a subscription renews and creates an invoice, Stripe sends the invoice.
webhook event. Stripe waits approximately one hour before finalizing the invoice and attempting payment or sending an email. During that delay, the invoice is a draft and can be edited. Follow the process to assign tax rates to that invoice.
If you have credit prorations, use the proration_
parameter in the (Invoice) Line Item object to reference to the original debit line items that the credit proration applies to. Use this reference to adjust the tax amounts correctly for credit prorations.
Adding tax rates to Checkout 
You can specify tax rates (Sales, VAT, GST, and others) in Checkout Sessions to apply taxes to subscriptions.
- Use fixed tax rates when you know the exact tax rate to charge your customers before they start the checkout process (for example, you only sell to customers in the UK and always charge 20% VAT).
- With the Prices API, you can use dynamic tax rates when you require more information from your customer (for example, their billing or shipping address) before determining the tax rate to charge. With dynamic tax rates, you create tax rates for different regions (for example, a 20% VAT tax rate for customers in the UK and a 7.25% sales tax rate for customers in California, US) and Stripe attempts to match your customer’s location to one of those tax rates.
You can use Stripe’s data exports to populate the periodic reports required for remittance. Visit Tax reporting and remittance for more information.