Files
songs2vid/.agents/skills/stripe-best-practices/references/tax.md
T
Atakan Doğan Özban 9404efd86c Align preview typography with FFmpeg output, add video/song title split, and ship OSS updates.
Separate YouTube video titles from on-video song/artist fields with Pro gating, serve curated fonts and watermark assets for 1:1 preview parity, and include billing/API/docs/deploy stack for self-hosted release.
2026-07-27 16:26:19 +02:00

13 KiB
Raw Blame History

Tax / Stripe Tax

Table of contents

  • When tax applies
  • Two-step setup
  • Verify before you trust automatic tax
  • Choosing a product tax code
  • Diagnose zero tax
  • Per-integration setup
  • Connect platforms and marketplaces
  • Threshold and nexus monitoring
  • Registration safety
  • If jurisdictions are unknown
  • If the region or tax type isnt supported

When tax applies

Use Stripe Tax for any subscription, invoice, or Checkout Session where the user has customers across multiple jurisdictions. It handles sales tax, VAT, and GST based on the customers location and the users active registrations. See the Tax overview for supported regions and tax types.

Two-step setup

  1. Add a registration for each jurisdiction where the user is obligated to collect tax, using the Tax Registrations API or the Dashboard.
  2. Pass automatic_tax: { enabled: true } on the Subscription, Invoice, or Checkout Session object.

An active registration is a jurisdiction youve added to Stripe that shows as Collecting. Its per-jurisdiction, and not the same as having a Stripe account.

Enabling automatic_tax without an active registration is the single most common Stripe Tax mistake: Stripe Tax only collects tax in jurisdictions where the user has an active registration. Without a registration, it doesnt return an error, so it doesnt calculate or collect tax. The user thinks tax is on while collecting nothing. Never enable automatic_tax and assume the user is set up. Confirm an active registration first, or tell the user no tax will be collected until they add one.

Traps to avoid: automatic_tax cant coexist with manual tax_rates (explicit rate objects) on the same object. Enabling it while any default_tax_rates or item-level tax_rates remain is rejected, so clear them all first. Its all-or-nothing, not per line item. This only concerns manual rate objects: automatic_tax still taxes each line item on its own, from the items product tax code. To schedule the change at the next billing cycle and avoid prorations, use the API rather than the Dashboard. For bulk migrations, use the Tax migration tool, which removes the tax rates for you.

Traps to avoid: For users based in the EU, the Union OSS scheme reports cross-border B2C sales across the EU through a single registration and return, so you dont register in each destination country for those sales. It doesnt cover domestic or B2B sales. The user still needs a domestic registration in their home country. Confirm the specifics with the users tax advisor.

Verify before you trust automatic tax

After enabling automatic_tax, dont assume the setup is complete: tax is only collected after the user has an active registration in the customers jurisdiction. Have the user confirm their registrations with the Tax Registrations API (or in the Dashboard). With none, tax wont be collected anywhere. The other prerequisites (origin and customer address, tax code, tax behavior) are covered in Stripe Tax setup.

Choosing a product tax code

A product tax code (PTC) tells Stripe how to tax a product.

  • Never invent, guess, or hardcode a txcd_ from memory. The exact value must come from Stripes canonical list: the Tax Codes API or the tax code guide.
  • Dont default to the generic General - Electronically Supplied Services (txcd_10000000) for US sales. Its too broad for US state-level taxability; pick a specific digital or SaaS code. See tax codes for digital products and tax codes for AI services.
  • Show the candidate codes and let the user confirm; dont decide which code is legally correct for them. (Tax code goes on the Product, tax_behavior on the Price. See product tax codes and tax behavior.)

Diagnose zero tax

When a transaction shows zero tax, first confirm automatic_tax is actually enabled on the object. If it isnt, Stripe doesnt calculate tax at all. If it is, read the taxability_reason on the line items taxes to see why. On a Checkout Session, that breakdown isnt returned by default: retrieve the session with expand[]=line_items.data.taxes.

The reason worth calling out is not_collecting, which is ambiguous: it means either no active registration in the customers jurisdiction (the usual cause; check registrations with the Tax Registrations API) or a Nontaxable product tax code (txcd_00000000) on the product. taxability_reason cant tell the two apart, so check the products tax code and rule out the Nontaxable code before concluding its a registration gap.

For the other reasons (exempt products or customers, reverse charge, unsupported regions, zero-rated), see zero tax amounts and reverse charges.

Per-integration setup

Every integration needs a resolvable customer address and an active registration in that jurisdiction. It also needs a product tax code and a tax_behavior, set on the product/price, or falling back to the accounts preset tax code and default tax behavior.

  • Checkout Sessions: set automatic_tax: { enabled: true }. For a new customer, Checkout collects the address it needs, so dont force billing_address_collection: 'required' (unnecessary for tax, and it adds checkout friction). For an existing or returning customer, Checkout uses their saved address by default; to tax the address entered at checkout instead, set customer_update: { address: 'auto' } and make sure Checkout actually collects a fresh address (a collected shipping address, or billing_address_collection: 'required' when you dont collect shipping), or it keeps using the saved one. See tax on Checkout.
  • Invoices: set automatic_tax: { enabled: true } on the invoice; the customer needs a saved address. See the Invoices API.
  • Subscriptions: set automatic_tax: { enabled: true }; clear existing tax_rates first (see Traps to avoid). See the Subscriptions API.
  • Payment Links: set automatic_tax: { enabled: true }.
  • Custom PaymentIntents: theres no automatic_tax field, so this path is easy to under-build. Create a tax calculation with the customers address, set the PaymentIntent amount to the calculation total, and link the calculation to the PaymentIntent. You must also record a tax transaction from the calculation after payment, or the sale never appears in tax reports: the simplified integration records the transaction and refund reversals automatically once the calculation is linked, while the custom integration records them yourself for line-item control.

For B2B or reverse-charge treatment, collect the customers tax ID (tax_id_collection: { enabled: true } on Checkout, or store it on the Customer). Without a valid tax ID, Stripe Tax treats a cross-border B2B sale as B2C and charges tax. See collect tax IDs.

Connect platforms and marketplaces

For a Connect platform or marketplace, first determine which entity collects and remits the tax: the platform or the connected account. This is a legal determination, so route the final call to the users tax advisor rather than inferring it from whether they call themselves a platform or a marketplace. The practical signal is who the merchant of record is, which follows the charge type: direct charges make the connected account the merchant of record, and destination charges usually make it the platform. Marketplace-facilitator rules can override this, so have the advisor confirm. See Stripe Tax with Connect for the decision.

Once the liable entity is known:

  • Set the liable entity with automatic_tax.liability on Checkout, Invoices, Subscriptions, or Payment Links: { type: 'self' } for the platform, or { type: 'account', account: '<id>' } for the connected account. Destination and separate charges support both; a platform-liable direct charge uses the gated { type: 'application' }. Custom PaymentIntents have no automatic_tax field, so follow the PaymentIntents path in the guides instead. Pick the guide by outcome: connected account collects, tax for platforms; platform collects, tax for marketplaces.
  • Registrations and tax settings belong to the liable entity. When the connected account is liable, confirm its tax settings status is active before enabling automatic_tax on its payments, and manage its registrations with the Tax Registrations API using the Stripe-Account header (or Connect embedded components).

Threshold and nexus monitoring

Stripes threshold monitoring highlights potential registration obligations (no public API yet). Present it as information and route the decision to the users tax advisor. Its up to the user to confirm whether registration is required; dont tell them they must register.

Registration safety

Guide, dont advise. Never tell a user where they must register or whether theyre legally obligated. Recommend they consult their tax advisor to determine their obligations.

  • The Tax Registrations API can list, create, update, and expire registrations (set expires_at to expire; theres no delete). A scheduled expiry can be changed, but an expiration that has taken effect is permanent (to collect again, the user adds a new registration), and theres no pause. A head office address is required before adding a registration.
  • Adding a registration in Stripe records where the user is already registered. It doesnt register them with the tax authority.
  • Creating or expiring a registration changes whether Stripe collects tax in that jurisdiction, but it doesnt register or deregister the user with the tax authority. The user must do that separately. Prepare the change and have the user confirm it; never create or expire a registration automatically.

How to register. Present the paths that fit the user and let them (with their tax advisor) choose. Dont pick for them.

  • Register themselves, then record it in Stripe: the user registers with the tax authority, then records it with the Tax Registrations API or the Dashboard. See Register for tax.
  • Ask Stripe to register (US only): for remote, out-of-state sellers with no physical presence in the state; no public API, requires a Tax Complete subscription, and doesnt support in-state registrations. See Use Stripe to register.
  • Register outside the US with Taxually: no public API; done through the Taxually app. See Register outside the US with Taxually.

Reporting and filing. Stripe Tax calculates and collects tax but doesnt file returns unless the user is on a filing product. Point users to the Dashboard tax reports and exports to reconcile and remit; filing runs through Stripe (US) or Taxually (non-US).

If jurisdictions are unknown

Dont guess which jurisdictions apply. Ask the user which states or countries they have customers in, then add a registration for each with the Tax Registrations API or the Dashboard.

If the region or tax type isnt supported

Check the supported countries list. If the jurisdiction isnt listed, tell the user:

  • Stripe Tax doesnt support that region yet
  • They can collect tax manually using tax_rates on the subscription or invoice instead (not alongside automatic_tax; you cant use both)
  • For unsupported tax types (customs duties, excise taxes), Stripe Tax doesnt apply, so those are out of scope

Dont attempt to approximate using a supported region as a proxy.