--- title: Collect taxes for recurring payments subtitle: Learn how to collect and report taxes for recurring payments. route: /tax/subscriptions --- # Collect taxes for recurring payments Learn how to collect and report taxes for recurring payments. 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](https://docs.stripe.com/products-prices/pricing-models.md), [prorations](https://docs.stripe.com/billing/subscriptions/prorations.md), [discounts](https://docs.stripe.com/billing/subscriptions/coupons.md), [trials](https://docs.stripe.com/billing/subscriptions/trials.md), and so on. This guide assumes you’re setting up Stripe Tax and Billing for the first time. See how to [update existing subscriptions](https://docs.stripe.com/tax/subscriptions/update.md). If you’re using Stripe Checkout to create new subscriptions, see how to [automatically collect tax on Checkout sessions](https://docs.stripe.com/tax/checkout.md), or watch the short video below: ## Estimate taxes and total When a customer first enters your checkout flow, you might not have their address information yet. In this case, [create a preview invoice](https://docs.stripe.com/api/invoices/create_preview.md) and set [customer_details.tax.ip_address](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-tax-ip_address) to let Stripe locate them using their IP address. In most cases, Stripe can resolve an IP address to a physical area, but its precision varies and might not reflect your customer’s actual location. We don’t recommend relying on a customer’s IP address to determine their address beyond an initial estimate. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new InvoiceCreatePreviewOptions { AutomaticTax = new InvoiceAutomaticTaxOptions { Enabled = true }, CustomerDetails = new InvoiceCustomerDetailsOptions { Tax = new InvoiceCustomerDetailsTaxOptions { IpAddress = "{{IP_ADDRESS}}" }, }, SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = new List { new InvoiceSubscriptionDetailsItemOptions { Price = "<>" }, }, }, }; var service = new InvoiceService(); Invoice invoice = service.CreatePreview(options); ``` ```go stripe.Key = "<>" params := &stripe.InvoiceCreatePreviewParams{ AutomaticTax: &stripe.InvoiceCreatePreviewAutomaticTaxParams{Enabled: stripe.Bool(true)}, CustomerDetails: &stripe.InvoiceCreatePreviewCustomerDetailsParams{ Tax: &stripe.InvoiceCreatePreviewCustomerDetailsTaxParams{ IPAddress: stripe.String("{{IP_ADDRESS}}"), }, }, SubscriptionDetails: &stripe.InvoiceCreatePreviewSubscriptionDetailsParams{ Items: []*stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ &stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{Price: stripe.String("<>")}, }, }, }; result, err := invoice.CreatePreview(params); ``` ```java Stripe.apiKey = "<>"; InvoiceCreatePreviewParams params = InvoiceCreatePreviewParams.builder() .setAutomaticTax(InvoiceCreatePreviewParams.AutomaticTax.builder().setEnabled(true).build()) .setCustomerDetails( InvoiceCreatePreviewParams.CustomerDetails.builder() .setTax( InvoiceCreatePreviewParams.CustomerDetails.Tax.builder() .setIpAddress("{{IP_ADDRESS}}") .build() ) .build() ) .setSubscriptionDetails( InvoiceCreatePreviewParams.SubscriptionDetails.builder() .addItem( InvoiceCreatePreviewParams.SubscriptionDetails.Item.builder() .setPrice("<>") .build() ) .build() ) .build(); Invoice invoice = Invoice.createPreview(params); ``` ```node const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.createPreview({ automatic_tax: { enabled: true, }, customer_details: { tax: { ip_address: '{{IP_ADDRESS}}', }, }, subscription_details: { items: [ { price: '<>', }, ], }, }); ``` ```python import stripe stripe.api_key = "<>" invoice = stripe.Invoice.create_preview( automatic_tax={"enabled": True}, customer_details={"tax": {"ip_address": "{{IP_ADDRESS}}"}}, subscription_details={"items": [{"price": "<>"}]}, ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->createPreview([ 'automatic_tax' => ['enabled' => true], 'customer_details' => ['tax' => ['ip_address' => '{{IP_ADDRESS}}']], 'subscription_details' => ['items' => [['price' => '<>']]], ]); ``` ```ruby Stripe.api_key = '<>' invoice = Stripe::Invoice.create_preview({ automatic_tax: {enabled: true}, customer_details: {tax: {ip_address: '{{IP_ADDRESS}}'}}, subscription_details: {items: [{price: '<>'}]}, }) ``` When your customer fills in their address details, set [customer_details.address](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-address) also. Use [customer_details.shipping](https://docs.stripe.com/api/invoices/create_preview.md#create_create_preview-customer_details-shipping) if you’re collecting shipping addresses. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new InvoiceCreatePreviewOptions { AutomaticTax = new InvoiceAutomaticTaxOptions { Enabled = true }, CustomerDetails = new InvoiceCustomerDetailsOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new InvoiceCustomerDetailsTaxOptions { IpAddress = "{{IP_ADDRESS}}" }, }, SubscriptionDetails = new InvoiceSubscriptionDetailsOptions { Items = new List { new InvoiceSubscriptionDetailsItemOptions { Price = "<>" }, }, }, }; var service = new InvoiceService(); Invoice invoice = service.CreatePreview(options); ``` ```go stripe.Key = "<>" params := &stripe.InvoiceCreatePreviewParams{ AutomaticTax: &stripe.InvoiceCreatePreviewAutomaticTaxParams{Enabled: stripe.Bool(true)}, CustomerDetails: &stripe.InvoiceCreatePreviewCustomerDetailsParams{ Address: &stripe.InvoiceCreatePreviewCustomerDetailsAddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.InvoiceCreatePreviewCustomerDetailsTaxParams{ IPAddress: stripe.String("{{IP_ADDRESS}}"), }, }, SubscriptionDetails: &stripe.InvoiceCreatePreviewSubscriptionDetailsParams{ Items: []*stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{ &stripe.InvoiceCreatePreviewSubscriptionDetailsItemParams{Price: stripe.String("<>")}, }, }, }; result, err := invoice.CreatePreview(params); ``` ```java Stripe.apiKey = "<>"; InvoiceCreatePreviewParams params = InvoiceCreatePreviewParams.builder() .setAutomaticTax(InvoiceCreatePreviewParams.AutomaticTax.builder().setEnabled(true).build()) .setCustomerDetails( InvoiceCreatePreviewParams.CustomerDetails.builder() .setAddress( InvoiceCreatePreviewParams.CustomerDetails.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( InvoiceCreatePreviewParams.CustomerDetails.Tax.builder() .setIpAddress("{{IP_ADDRESS}}") .build() ) .build() ) .setSubscriptionDetails( InvoiceCreatePreviewParams.SubscriptionDetails.builder() .addItem( InvoiceCreatePreviewParams.SubscriptionDetails.Item.builder() .setPrice("<>") .build() ) .build() ) .build(); Invoice invoice = Invoice.createPreview(params); ``` ```node const stripe = require('stripe')('<>'); const invoice = await stripe.invoices.createPreview({ automatic_tax: { enabled: true, }, customer_details: { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { ip_address: '{{IP_ADDRESS}}', }, }, subscription_details: { items: [ { price: '<>', }, ], }, }); ``` ```python import stripe stripe.api_key = "<>" invoice = stripe.Invoice.create_preview( automatic_tax={"enabled": True}, customer_details={ "address": { "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, "tax": {"ip_address": "{{IP_ADDRESS}}"}, }, subscription_details={"items": [{"price": "<>"}]}, ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $invoice = $stripe->invoices->createPreview([ 'automatic_tax' => ['enabled' => true], 'customer_details' => [ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['ip_address' => '{{IP_ADDRESS}}'], ], 'subscription_details' => ['items' => [['price' => '<>']]], ]); ``` ```ruby Stripe.api_key = '<>' invoice = Stripe::Invoice.create_preview({ automatic_tax: {enabled: true}, customer_details: { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {ip_address: '{{IP_ADDRESS}}'}, }, subscription_details: {items: [{price: '<>'}]}, }) ``` Check the [automatic_tax.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of the invoice. If the status is `requires_location_inputs`, 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](https://docs.stripe.com/api/invoices/object.md#invoice_object-total) is how much your customer pays and [tax](https://docs.stripe.com/api/invoices/object.md#invoice_object-tax) is the sum of all tax amounts on the invoice. If you want a breakdown of taxes, see [total_tax_amounts](https://docs.stripe.com/api/invoices/object.md#invoice_object-total_tax_amounts). All amounts are in cents. 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](https://docs.stripe.com/tax/registering.md) and learn more about [zero tax amounts and reverse charges](https://docs.stripe.com/tax/zero-tax.md). ## Collect customer information 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](https://docs.stripe.com/js/elements_object/create_without_intent): ```javascript const stripe = Stripe("<>"); const elements = stripe.elements({ mode: 'subscription', currency: '{{CURRENCY}}', amount: {{TOTAL}}, }); ``` Next, [create an Address Element](https://docs.stripe.com/js/elements_object/create_address_element) and [a Payment Element](https://docs.stripe.com/js/elements_object/create_payment_element) and [mount](https://docs.stripe.com/js/element/mount) both: ```javascript 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](https://docs.stripe.com/js/element/events/on_change?type=paymentElement#element_on_change-event) on the Address Element. When the address changes, [re-estimate](https://docs.stripe.com/tax/subscriptions.md?estimate=after#estimate-taxes-total) the taxes and the total. ```javascript 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... }); ``` 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](https://docs.stripe.com/rate-limits.md), wait for some time after the last `change` event before re-estimating the taxes and the total. ## Handle submission When your customer submits the form, call [elements.submit()](https://docs.stripe.com/js/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. ```javascript 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 saveCustomerDetails(customerDetails); // See the "Create subscription" section below to implement this server-side. const { clientSecret } = await createSubscription(); const { error: confirmError } = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: {{RETURN_URL}}, }, }); 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. }); ``` ## Save customer details [Update](https://docs.stripe.com/api/customers/update.md) your `Customer` object using the details you’ve collected from your customer, so that Stripe Tax can determine their precise location for accurate results. 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](https://docs.stripe.com/api/customers/create.md) one now. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new CustomerUpdateOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new CustomerTaxOptions { ValidateLocation = "immediately" }, }; var service = new CustomerService(); Customer customer = service.Update("<>", options); ``` ```go stripe.Key = "<>" params := &stripe.CustomerParams{ Address: &stripe.AddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.CustomerTaxParams{ValidateLocation: stripe.String("immediately")}, }; result, err := customer.Update("<>", params); ``` ```java Stripe.apiKey = "<>"; Customer resource = Customer.retrieve("<>"); CustomerUpdateParams params = CustomerUpdateParams.builder() .setAddress( CustomerUpdateParams.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( CustomerUpdateParams.Tax.builder() .setValidateLocation(CustomerUpdateParams.Tax.ValidateLocation.IMMEDIATELY) .build() ) .build(); Customer customer = resource.update(params); ``` ```node const stripe = require('stripe')('<>'); const customer = await stripe.customers.update( '<>', { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { validate_location: 'immediately', }, } ); ``` ```python import stripe stripe.api_key = "<>" customer = stripe.Customer.modify( "<>", address={ "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, tax={"validate_location": "immediately"}, ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->update( '<>', [ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['validate_location' => 'immediately'], ] ); ``` ```ruby Stripe.api_key = '<>' customer = Stripe::Customer.update( '<>', { address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {validate_location: 'immediately'}, }, ) ``` If your customer has other existing subscriptions with automatic tax enabled and you update their address information, the tax and total amounts on their future invoices might be different. This is because tax rates vary depending on customer location. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new CustomerCreateOptions { Address = new AddressOptions { Line1 = "{{LINE1}}", Line2 = "{{LINE2}}", City = "{{CITY}}", State = "{{STATE}}", PostalCode = "{{POSTAL_CODE}}", Country = "{{COUNTRY}}", }, Tax = new CustomerTaxOptions { ValidateLocation = "immediately" }, }; var service = new CustomerService(); Customer customer = service.Create(options); ``` ```go stripe.Key = "<>" params := &stripe.CustomerParams{ Address: &stripe.AddressParams{ Line1: stripe.String("{{LINE1}}"), Line2: stripe.String("{{LINE2}}"), City: stripe.String("{{CITY}}"), State: stripe.String("{{STATE}}"), PostalCode: stripe.String("{{POSTAL_CODE}}"), Country: stripe.String("{{COUNTRY}}"), }, Tax: &stripe.CustomerTaxParams{ValidateLocation: stripe.String("immediately")}, }; result, err := customer.New(params); ``` ```java Stripe.apiKey = "<>"; CustomerCreateParams params = CustomerCreateParams.builder() .setAddress( CustomerCreateParams.Address.builder() .setLine1("{{LINE1}}") .setLine2("{{LINE2}}") .setCity("{{CITY}}") .setState("{{STATE}}") .setPostalCode("{{POSTAL_CODE}}") .setCountry("{{COUNTRY}}") .build() ) .setTax( CustomerCreateParams.Tax.builder() .setValidateLocation(CustomerCreateParams.Tax.ValidateLocation.IMMEDIATELY) .build() ) .build(); Customer customer = Customer.create(params); ``` ```node const stripe = require('stripe')('<>'); const customer = await stripe.customers.create({ address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: { validate_location: 'immediately', }, }); ``` ```python import stripe stripe.api_key = "<>" customer = stripe.Customer.create( address={ "line1": "{{LINE1}}", "line2": "{{LINE2}}", "city": "{{CITY}}", "state": "{{STATE}}", "postal_code": "{{POSTAL_CODE}}", "country": "{{COUNTRY}}", }, tax={"validate_location": "immediately"}, ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $customer = $stripe->customers->create([ 'address' => [ 'line1' => '{{LINE1}}', 'line2' => '{{LINE2}}', 'city' => '{{CITY}}', 'state' => '{{STATE}}', 'postal_code' => '{{POSTAL_CODE}}', 'country' => '{{COUNTRY}}', ], 'tax' => ['validate_location' => 'immediately'], ]); ``` ```ruby Stripe.api_key = '<>' customer = Stripe::Customer.create({ address: { line1: '{{LINE1}}', line2: '{{LINE2}}', city: '{{CITY}}', state: '{{STATE}}', postal_code: '{{POSTAL_CODE}}', country: '{{COUNTRY}}', }, tax: {validate_location: 'immediately'}, }) ``` The [tax.validate_location](https://docs.stripe.com/api/customers/update.md#update_customer-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](https://docs.stripe.com/error-codes.md#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](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of your preview invoices as [advised](#estimate-taxes-total) previously, this additional validation won’t ever fail. However, it’s good practice to set `tax[validate_location]="immediately"` whenever you’re creating or updating a `Customer` object. ## Create subscription [Create](https://docs.stripe.com/api/subscriptions/create.md) a subscription with automatic tax enabled. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new SubscriptionCreateOptions { AutomaticTax = new SubscriptionAutomaticTaxOptions { Enabled = true }, Customer = "<>", Items = new List { new SubscriptionItemOptions { Price = "<>" }, }, PaymentSettings = new SubscriptionPaymentSettingsOptions { SaveDefaultPaymentMethod = "on_subscription", }, Expand = new List { "latest_invoice.payment_intent" }, }; var service = new SubscriptionService(); Subscription subscription = service.Create(options); ``` ```go stripe.Key = "<>" params := &stripe.SubscriptionParams{ AutomaticTax: &stripe.SubscriptionAutomaticTaxParams{Enabled: stripe.Bool(true)}, Customer: stripe.String("<>"), Items: []*stripe.SubscriptionItemsParams{ &stripe.SubscriptionItemsParams{Price: stripe.String("<>")}, }, PaymentSettings: &stripe.SubscriptionPaymentSettingsParams{ SaveDefaultPaymentMethod: stripe.String(string(stripe.SubscriptionPaymentSettingsSaveDefaultPaymentMethodOnSubscription)), }, }; params.AddExpand("latest_invoice.payment_intent") result, err := subscription.New(params); ``` ```java Stripe.apiKey = "<>"; SubscriptionCreateParams params = SubscriptionCreateParams.builder() .setAutomaticTax(SubscriptionCreateParams.AutomaticTax.builder().setEnabled(true).build()) .setCustomer("<>") .addItem(SubscriptionCreateParams.Item.builder().setPrice("<>").build()) .setPaymentSettings( SubscriptionCreateParams.PaymentSettings.builder() .setSaveDefaultPaymentMethod( SubscriptionCreateParams.PaymentSettings.SaveDefaultPaymentMethod.ON_SUBSCRIPTION ) .build() ) .addExpand("latest_invoice.payment_intent") .build(); Subscription subscription = Subscription.create(params); ``` ```node const stripe = require('stripe')('<>'); const subscription = await stripe.subscriptions.create({ automatic_tax: { enabled: true, }, customer: '<>', items: [ { price: '<>', }, ], payment_settings: { save_default_payment_method: 'on_subscription', }, expand: ['latest_invoice.payment_intent'], }); ``` ```python import stripe stripe.api_key = "<>" subscription = stripe.Subscription.create( automatic_tax={"enabled": True}, customer="<>", items=[{"price": "<>"}], payment_settings={"save_default_payment_method": "on_subscription"}, expand=["latest_invoice.payment_intent"], ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $subscription = $stripe->subscriptions->create([ 'automatic_tax' => ['enabled' => true], 'customer' => '<>', 'items' => [['price' => '<>']], 'payment_settings' => ['save_default_payment_method' => 'on_subscription'], 'expand' => ['latest_invoice.payment_intent'], ]); ``` ```ruby Stripe.api_key = '<>' subscription = Stripe::Subscription.create({ automatic_tax: {enabled: true}, customer: '<>', items: [{price: '<>'}], payment_settings: {save_default_payment_method: 'on_subscription'}, expand: ['latest_invoice.payment_intent'], }) ``` The [latest_invoice.payment_intent.client_secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-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. 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](https://docs.stripe.com/api/invoices/object.md#invoice_object-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_incomplete` for the [payment_behavior](https://docs.stripe.com/api/subscriptions/create.md#create_subscription-payment_behavior) when you’re creating your subscription and confirm the payment intent using [stripe.confirmPayment()](https://docs.stripe.com/js/payment_intents/confirm_payment) as shown. See [Billing collection methods](https://docs.stripe.com/billing/collection-method.md) for more information. ## Update your products and prices 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](https://dashboard.stripe.com/settings/tax). For more information, see [Specify product tax codes and tax behaviour](https://docs.stripe.com/tax/products-prices-tax-codes-tax-behavior.md). ## Handle refunds When you create a refund for an Invoice payment, Stripe Tax automatically reduces your tax liability. Alternatively, you can issue [Credit Notes](https://docs.stripe.com/api/credit_notes/object.md) to track tax liability decreases and provide records to your customers. To refund an amount associated with an invoice total, create a Credit Note and a Refund. Create a Credit Note and a [Refund](https://docs.stripe.com/api/refunds/object.md) together by calling [create Credit Note](https://docs.stripe.com/api/credit_notes/create.md) and providing a `refund_amount` value. ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new CreditNoteCreateOptions { Invoice = "<>", RefundAmount = 1000 }; var service = new CreditNoteService(); CreditNote creditNote = service.Create(options); ``` ```go stripe.Key = "<>" params := &stripe.CreditNoteParams{ Invoice: stripe.String("<>"), RefundAmount: stripe.Int64(1000), }; result, err := creditnote.New(params); ``` ```java Stripe.apiKey = "<>"; CreditNoteCreateParams params = CreditNoteCreateParams.builder().setInvoice("<>").setRefundAmount(1000L).build(); CreditNote creditNote = CreditNote.create(params); ``` ```node const stripe = require('stripe')('<>'); const creditNote = await stripe.creditNotes.create({ invoice: '<>', refund_amount: 1000, }); ``` ```python import stripe stripe.api_key = "<>" credit_note = stripe.CreditNote.create( invoice="<>", refund_amount=1000, ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $creditNote = $stripe->creditNotes->create([ 'invoice' => '<>', 'refund_amount' => 1000, ]); ``` ```ruby Stripe.api_key = '<>' credit_note = Stripe::CreditNote.create({ invoice: '<>', refund_amount: 1000, }) ``` [Create a Refund](https://docs.stripe.com/api/refunds/create.md), then include its ID when you create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md). In this case, don’t include a `refund_amount` value. Stripe Tax automatically distributes the total refund amount between taxes and the net amount. If you want to refund an amount associated with an invoice line item, first calculate the [total](https://docs.stripe.com/api/credit_notes/object.md#credit_note_object-total) and [total_excluding_tax](https://docs.stripe.com/api/credit_notes/object.md#credit_note_object-total_excluding_tax) amounts by calling [preview Credit Note](https://docs.stripe.com/api/credit_notes/preview.md). ```dotnet StripeConfiguration.ApiKey = "<>"; var options = new CreditNotePreviewOptions { Invoice = "<>", Lines = new List { new CreditNoteLineOptions { Type = "invoice_line_item", InvoiceLineItem = "{{line item id from invoice}}", Amount = 1000, }, }, }; var service = new CreditNoteService(); CreditNote creditNote = service.Preview(options); ``` ```go stripe.Key = "<>" params := &stripe.CreditNotePreviewParams{ Invoice: stripe.String("<>"), Lines: []*stripe.CreditNotePreviewLineParams{ &stripe.CreditNotePreviewLineParams{ Type: stripe.String("invoice_line_item"), InvoiceLineItem: stripe.String("{{line item id from invoice}}"), Amount: stripe.Int64(1000), }, }, }; result, err := creditnote.Preview(params); ``` ```java Stripe.apiKey = "<>"; CreditNotePreviewParams params = CreditNotePreviewParams.builder() .setInvoice("<>") .addLine( CreditNotePreviewParams.Line.builder() .setType(CreditNotePreviewParams.Line.Type.INVOICE_LINE_ITEM) .setInvoiceLineItem("{{line item id from invoice}}") .setAmount(1000L) .build() ) .build(); CreditNote creditNote = CreditNote.preview(params); ``` ```node const stripe = require('stripe')('<>'); const creditNote = await stripe.creditNotes.preview({ invoice: '<>', lines: [ { type: 'invoice_line_item', invoice_line_item: '{{line item id from invoice}}', amount: 1000, }, ], }); ``` ```python import stripe stripe.api_key = "<>" credit_note = stripe.CreditNote.preview( invoice="<>", lines=[ { "type": "invoice_line_item", "invoice_line_item": "{{line item id from invoice}}", "amount": 1000, }, ], ) ``` ```php $stripe = new \Stripe\StripeClient('<>'); $creditNote = $stripe->creditNotes->preview([ 'invoice' => '<>', 'lines' => [ [ 'type' => 'invoice_line_item', 'invoice_line_item' => '{{line item id from invoice}}', 'amount' => 1000, ], ], ]); ``` ```ruby Stripe.api_key = '<>' credit_note = Stripe::CreditNote.preview({ invoice: '<>', lines: [ { type: 'invoice_line_item', invoice_line_item: '{{line item id from invoice}}', amount: 1000, }, ], }) ``` Then, create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md) and a [Refund](https://docs.stripe.com/api/refunds/object.md). Create a Credit Note and a [Refund](https://docs.stripe.com/api/refunds/object.md) together by calling [create Credit Note](https://docs.stripe.com/api/credit_notes/create.md) and providing a `refund_amount` value. [Create a Refund](https://docs.stripe.com/api/refunds/create.md) using the `total` calculated by the Credit Note preview, then include its ID when you create a [Credit Note](https://docs.stripe.com/api/credit_notes/object.md). In this case, don’t include a `refund_amount` value. ## 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](https://docs.stripe.com/api/events/types.md#event_types-invoice.finalization_failed) events. If the [automatic_tax.status](https://docs.stripe.com/api/invoices/object.md#invoice_object-automatic_tax-status) of the invoice is `requires_location_inputs`, 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](https://docs.stripe.com/billing/subscriptions/webhooks.md) to learn more. ## See Also * [Update existing subscriptions](https://docs.stripe.com/tax/subscriptions/update.md) * [Use Stripe Tax with Connect](https://docs.stripe.com/tax/connect.md) * [Calculate tax in your custom checkout flow](https://docs.stripe.com/tax/custom.md)