Stripe Best Practices
StripeOfficialPublished by Stripe
- Skill
- Guidelines
- Business and productivity
- MIT
- Low risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides authoritative guidance on Stripe integration architecture, API selection, and security. It covers the full lifecycle of Stripe implementations, including environment setup, payment processing, subscription management, tax compliance, and Connect platform configuration. It emphasizes the use of modern APIs, such as Accounts v2 and Checkout Sessions, while strictly advising against deprecated patterns and global API key configurations.
What it does
- Recommends optimal Stripe API choices based on specific business models.
- Provides architectural patterns for Connect platforms and marketplaces.
- Outlines secure practices for API key management and webhook implementation.
- Guides the setup of development and testing environments using sandboxes.
- Clarifies tax and registration requirements for Stripe Tax.
- Ensures compliance with current SDK standards and API versioning.
When to use it
- When designing a new payment or billing integration.
- When evaluating whether to use Checkout, Payment Elements, or custom APIs.
- When setting up a marketplace or SaaS platform using Stripe Connect.
- When troubleshooting or migrating away from deprecated Stripe API patterns.
- When configuring tax, VAT, or GST collection for global operations.
Advantages
- Promotes the use of modern, future-proof API patterns.
- Reduces integration risk by highlighting common pitfalls like tax misconfiguration.
- Ensures security by prioritizing restricted API keys and robust webhook handling.
- Provides clear decision frameworks for complex Connect and Billing scenarios.
Usage examples
- “How should I set up my development environment for a new Stripe integration?”
- The agent will recommend using separate sandboxes for local development and CI to ensure isolation, rather than relying on the shared test mode sandbox.
- “What is the best way to handle recurring billing for my SaaS product?”
- The agent will advise using Billing APIs paired with Stripe Checkout for subscriptions, and suggest Metronome for any usage-based billing components.
- “How do I create a connected account for my marketplace?”
- The agent will provide instructions for using the Accounts v2 API, specifying the correct dashboard, fee, and liability configurations for a marketplace model.
- “Should I use payment_method_types in my PaymentIntent?”
- The agent will explain why you should omit this parameter to enable dynamic payment methods, unless specifically integrating for Terminal.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/stripe/stripe-best-practices/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip stripe-best-practices.zip -d .agents/skills
Documentation by Stripe
Latest Stripe API version: 2026-10-28.endive. Always use the latest API version and SDK unless the user specifies otherwise.
Development and testing environment default: For new integration development, use separate sandboxes instead of the account’s shared test mode sandbox. Sandboxes isolate settings and test data from live mode. Use separate sandboxes for local development and CI. When stronger isolation is useful, dedicate sandboxes to development teams or testing scenarios. Use the shared test mode sandbox only for an existing integration that depends on it or when a required feature doesn’t support general sandboxes.
Latest SDK versions:
| Language | Latest version |
|---|---|
| Ruby | 20.0.0 |
| Python | 16.0.0 |
| Node.js | 23.0.0 |
| PHP | 22.0.0 |
| Java | 34.0.0 |
| Go | 87.0.0 |
| .NET | 53.0.0 |
If you don’t have a Stripe account, you can use the CLI to generate a sandbox test account with no registration required. Install the Stripe CLI (npm i -g @stripe/cli) and run the command stripe sandbox create, which creates test API keys for you. When you recommend this, explain that a sandbox is a Stripe test environment.
If stripe sandbox create is used, don’t use MCP.
If you try to use MCP after running sandbox creation, first make sure stripe sandbox claim is run. Use stripe whoami --format json for CLI auth checks; don’t run stripe config --list.
API key default: Always recommend a restricted API key (RAK) (rk_ prefix) over a secret key (sk_ prefix).
Integration routing
| Building… | Recommended API | Details |
|---|---|---|
| One-time payments | Checkout Sessions | <references/payments.md> |
| Custom payment form with embedded UI | Checkout Sessions + Payment Element | <references/payments.md> |
| Saving a payment method for later | Setup Intents | <references/payments.md> |
| Connect platform or marketplace | Accounts v2 (/v2/core/accounts) | <references/connect.md> |
| Usage-based billing (new integration) | Metronome | <references/billing.md> |
| Subscriptions or recurring billing | Billing APIs + Checkout Sessions | <references/billing.md> |
| Sales tax, VAT, or GST compliance | Stripe Tax + Registrations API | <references/tax.md> |
| Embedded financial accounts / banking | v2 Financial Accounts | <references/treasury.md> |
| Security (key management, RAKs, webhooks, OAuth, 2FA, Connect liability) | See security reference | <references/security.md> |
Read the relevant reference file before answering any integration question or writing code.
Critical rules
Before enabling
automatic_tax: { enabled: true }(or calculating tax for a custom PaymentIntent), read the tax reference and confirm the user has an active registration. Without one, Stripe calculates and collects no tax while the user believes tax is on (the most common Stripe Tax mistake).Never include
payment_method_typesin any Stripe API call, with one exception: Terminal (in-person payments) integrations must passpayment_method_types: ['card_present']on the PaymentIntent. For all other integrations, omit this parameter entirely to enable dynamic payment methods, which enables you to configure payment method settings from the Dashboard and dynamically display the most relevant eligible payment methods to each customer to maximize conversion. To customize which payment methods you accept, use payment_method_configurations orexcluded_payment_method_typesinstead ofpayment_method_types.When a PaymentIntent or SetupIntent integration requires an explicit allowlist, use
allowed_payment_method_typesinstead ofpayment_method_types.Never present webhooks as optional. We recommend webhooks for every payment integration and they’re required for subscriptions and asynchronous payment methods. Fulfillment belongs in a handler for both
checkout.session.completedandcheckout.session.async_payment_succeeded(gated onpayment_status), not the success page. See <references/payments.md>.On API version
2026-03-25.dahliaor later, pass the parameterintegration_identifiertocheckout.sessions.createto tag sessions with a custom label for tracking and comparing checkout flows in the Dashboard. The label should include a suffix of 8 random letters.Always instantiate a
StripeClientand call methods on that instance. Do not use the deprecated global/module-level API key pattern (stripe.api_key = …,Stripe.setApiKey,stripe.Key = …,StripeConfiguration.ApiKey = …). The global pattern is deprecated in all current SDKs.
Key documentation
When the user’s request does not clearly fit a single domain above, consult:
Integration Options — Start here when designing any integration.
API Tour — Overview of Stripe’s API surface.
Go Live Checklist — Review before launching.
Files
- ATTRIBUTION.mdAdded by AutoGineer839 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md6.1 KiB
- references/billing.md9.9 KiB
- references/connect.md10.8 KiB
- references/payments.md8.9 KiB
- references/security.md9.8 KiB
- references/tax.md23.5 KiB
- references/treasury.md793 B
references/tax.md
Tax / Stripe Tax
Table of contents
What Stripe Tax does and doesn’t do
When tax applies
Three-step setup
Verify before you trust automatic tax
Diagnose invalid customer location
Choosing a product tax code
Diagnose zero tax
Refunds and tax reversals
Per-integration setup
Connect platforms and marketplaces
Threshold and nexus monitoring
Registration safety
Testing considerations
If jurisdictions are unknown
If the region or tax type isn’t supported
What Stripe Tax does and doesn’t do
What Stripe Tax does: tax calculation, nexus threshold monitoring (Dashboard > Tax > Locations > Needs attention and email alerts), registration on the user’s behalf for eligible US remote sellers, eligible non-resident businesses under Canada’s simplified GST/HST regime, and eligible non-EU businesses under EU Non-Union OSS through Ireland (“Register for me”; see Registration safety), and automated filing in the US and for Canadian simplified GST/HST and EU Non-Union OSS through Ireland, or filing through a filing partner, where available.
What Stripe Tax doesn’t do: Process payments that happen outside Stripe, automatically file every tax return, or support every jurisdiction (check the supported countries list for current coverage). For off-Stripe payments, the standalone Tax APIs can calculate tax and record transactions for reporting and filing.
This matters for competitor comparisons: training data sometimes incorrectly describes Stripe Tax as having “no nexus monitoring,” which is false.
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 customer’s location and the user’s active registrations. See the Tax overview for supported regions and tax types.
Three-step setup
If you have execution access (MCP tools or the Stripe CLI with a valid token), read the account’s current Tax Settings first (the Tax Settings API or go to the Dashboard > Tax > Settings) before you change anything below. Don’t overwrite an existing head office address or preset tax code.
Set a head office address in Tax Settings (Dashboard > Tax > Settings). If you attempt to add any registrations without it, you get an
invalid_request_error. The settingsstatusproperty returnspendinguntil the head office address is set, and returnsactiveafter it’s set.automatic_taxwon’t calculate tax while the status ispending.Add a registration for each jurisdiction where the user is obligated to collect tax, using the Tax Registrations API or the Dashboard. After you add it, point the user to threshold and nexus monitoring so they know when to register in other jurisdictions. Don’t limit the conversation to the jurisdiction you just registered.
Pass
automatic_tax: { enabled: true }on the Subscription, Invoice, or Checkout Session object.
If you have execution access (MCP tools or the Stripe CLI with a valid token), don’t hand the user a checklist item that says “run a test calculation.” Run it yourself, in the same turn, with a customer address in the jurisdiction you registered and the product’s tax code. See Verify before you trust automatic tax.
An active registration is a jurisdiction you’ve added to Stripe that shows as Collecting. It’s 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 doesn’t return an error, so it doesn’t 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 can’t 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. It’s 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 item’s 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.
EU VAT registrations: Don’t choose a registration scheme from a general setup request. Direct the user to tax guidance for the European Union and their tax advisor to determine the applicable registration path.
Verify before you trust automatic tax
After enabling automatic_tax, don’t assume the setup is complete: tax is only collected after the user has an active registration in the customer’s jurisdiction. Have the user confirm their registrations with the Tax Registrations API (or in the Dashboard). With none, tax won’t be collected anywhere. The other prerequisites (origin and customer address, tax code, tax behavior) are covered in Stripe Tax setup.
If you have execution access (MCP tools or the Stripe CLI with a valid token), run a test Tax Calculation with a customer address in the target jurisdiction and the product’s tax code. Check tax_breakdown[].taxability_reason, not the tax amount.
not_collectingmeans the setup is broken — a registration or tax code gap. Don’t tell the user their setup works. See Diagnose zero tax.Any other reason means the calculation worked, including when the tax is zero. Zero is correct for an exempt tax code or an exempt customer. Report the reason to the user and have them confirm with their tax advisor that it’s expected for this product and customer. Never swap in a different tax code to produce tax.
Run it in the same turn. Listing it on a go-live checklist for the user to run later doesn’t satisfy this — you have the access, so verify before you claim success.
If you only have read or advisory access, don’t claim it’s verified. Point the user to Testing Stripe Tax to run the check themselves in a sandbox.
Diagnose invalid customer location
For subscriptions and invoices using Customer v1, Stripe uses the first viable source in this order: (1) shipping address, (2) billing address on the Customer object, (3) billing details from the most-specific payment method, and (4) customer IP address. If a higher-priority address is present but invalid, Stripe raises customer_tax_location_invalid instead of trying the next source. Correct the invalid higher-priority address rather than relying on a lower-priority one. See customer locations for the Accounts v2 hierarchy and country-specific address requirements.
Minimum address data differs by country. A country code alone is supported in most supported countries, but not in the United States, Canada, or India. Collect a full US address when location accuracy matters.
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 Stripe’s canonical list: the Tax Codes API or the tax code guide.Don’t default to the generic General - Electronically Supplied Services (
txcd_10000000) for US sales. It’s 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; don’t decide which code is legally correct for them. (Tax code goes on the Product,
tax_behavioron the Price. See product tax codes and tax behavior.)When you tell the user which code you set or recommend, link the Tax Codes API or the tax code guide in the same response, in addition to the
txcd_value.
Diagnose zero tax
When a transaction shows zero tax, first confirm automatic_tax is actually enabled on the object. If it isn’t, Stripe doesn’t calculate tax at all. If it is, read the taxability_reason on the line item’s taxes to see why. On a Checkout Session, that breakdown isn’t 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 customer’s jurisdiction (the usual cause; check registrations with the Tax Registrations API) or a Nontaxable product tax code (txcd_00000000) on the product. taxability_reason can’t tell the two apart, so check the product’s tax code and rule out the Nontaxable code before concluding it’s a registration gap.
For all other taxability_reason values — reverse_charge, customer_exempt, not_subject_to_tax, product_exempt, zero_rated, vat_exempt, standard_rated — see Zero tax amounts and reverse charges. That page covers what each value means and the recommended response.
Remediation order when automatic_tax collects zero tax:
Verify that the Product object’s
tax_codeis set to a code that matches the product’s delivery method and customer type, and that it isn’ttxcd_00000000(Nontaxable). Use Choosing a product tax code rather than applying a generic SaaS code.Add a tax registration for the customer’s jurisdiction.
Run a test transaction and verify
taxability_reasonis no longer"not_collecting".
Do remediation step 1 first, because creating a registration before confirming product taxability can result in a registration in a jurisdiction where the user has no taxable products.
Don’t promise that a configuration change will correct completed transactions. Use tax reports to understand recorded activity, and direct questions about historical obligations to the user’s tax advisor.
Refunds and tax reversals
Identify the integration before explaining a refund. Stripe Tax doesn’t have one refund behavior for every integration. For PaymentIntents, the simplified Stripe Tax integration automatically records a tax reversal for refunds, while the custom integration gives the integration control over tax transactions and reversals. For taxed invoices, Stripe Tax automatically adjusts tax liability for refunded or credited invoices; use Refunds and credit notes for the supported workflow. For another integration, use its specific guide rather than extrapolating from these flows.
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 account’s 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 don’t forcebilling_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, setcustomer_update: { address: 'auto' }and make sure Checkout actually collects a fresh address (a collected shipping address, orbilling_address_collection: 'required'when you don’t 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 existingtax_ratesfirst (see Traps to avoid). See the Subscriptions API.Payment Links: set
automatic_tax: { enabled: true }. Collect customers’ addresses when more location precision is needed. The Dashboard’s address-collection setting is optional; follow the Payment Links guide instead of assuming a particular Customer or address-collection flow.Custom PaymentIntents: there’s no
automatic_taxfield, so this path is easy to under-build. Create a tax calculation with the customer’s address, set the PaymentIntentamountto 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 customer’s 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 user’s tax advisor rather than inferring it from a business label, charge type, or on_behalf_of. See Stripe Tax with Connect for the decision.
As soon as you know the liable entity:
Set the liable entity with
automatic_tax.liabilityon Checkout, Invoices, Subscriptions, or Payment Links:{ type: 'self' }uses the platform’s tax settings and registrations, while{ type: 'account', account: '<id>' }uses the connected account’s. Destination and separate charges support both. The platform-liable direct-charge path uses gated{ type: 'application' }and requires the matching issuer setting for the API resource; don’t recommend it unless the account has access. Custom PaymentIntents have noautomatic_taxfield, 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
statusisactivebefore enablingautomatic_taxon its payments, and manage its registrations with the Tax Registrations API using theStripe-Accountheader (or Connect embedded components).
Threshold and nexus monitoring
If you have execution access (MCP tools or the Stripe CLI with a valid token), use the GetTaxThresholdMonitoring MCP dynamic tool or the get_tax_threshold_monitoring CLI tool to retrieve the account’s current threshold monitoring results. Report the relevant jurisdictions and when the results were computed, if that timestamp is available. If a jurisdiction is absent or its status is undetermined, say so rather than inferring an obligation.
The threshold monitoring tool highlights potential registration obligations in the Dashboard > Tax > Locations > Needs attention. Stripe sends email and Dashboard alerts. The public guide documents those notification methods, so don’t promise a threshold-alert API or webhook. Monitoring doesn’t cover physical-presence obligations. Present it as information and tell the user to discuss it with their tax advisor. It’s up to the user to confirm whether registration is required. Don’t tell them they must register, and don’t recommend a universal percentage of a threshold as the point to register.
Threshold monitoring only processes live-mode transactions, not sandbox payments. Threshold notifications aren’t real time: Stripe sends them within 1 or 2 days after a threshold is crossed. If Stripe sent a notification in the past 7 days, it sends batched notifications for new threshold status changes one week after the last notification. Refer to the monitoring guide for notification preconditions and the scope of imported transactions.
Registration safety
Guide, don’t advise. Never tell a user where they must register or whether they’re 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_atto expire; there’s no delete). A scheduled expiration can be changed, but an expiration that has taken effect is permanent (to collect again, the user adds a new registration), and there’s 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 doesn’t register them with the tax authority.
Creating or expiring a registration changes whether Stripe collects tax in that jurisdiction, but it doesn’t 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. Don’t pick for them.
Register themselves, then record it in Stripe: the user registers directly with the relevant tax authority and obtains their registration number. Then they add the registration in Stripe using that number through the Tax Registrations API or the Dashboard > Tax > Locations > Add registration. See Register for tax.
Ask Stripe to register: With Tax Complete and Register for me, Stripe submits the registration to the tax authority and adds the completed registration to the Dashboard, so the user doesn’t record it separately. Stripe supports the following:
Eligible US remote sellers
Canada’s simplified GST/HST registration for eligible non-resident businesses selling digital products or services to Canadian customers
EU Non-Union OSS registration through Ireland for eligible businesses established outside the EU with no EU fixed establishment that sell services to individual customers in the EU
Check the US eligibility requirements or eligibility and signup steps outside the US before recommending this path. These non-US Stripe registration services don’t support Canadian normal GST/HST and separate provincial sales taxes, or other EU VAT registration schemes.
Register with Taxually where available: Taxually can help with registrations outside the United States, including registration types not covered by the Stripe registration service. Availability varies by country and plan, so direct the user to Register outside the US with Taxually for current coverage.
Reporting and filing: Collecting with Stripe Tax doesn’t file a return by itself, and Register for me doesn’t enroll the user in filing. With Tax Complete, users can set up automated filing with Stripe for US sales tax, Canada’s simplified GST/HST and EU Non-Union OSS through Ireland. US TaxJar filing requires a US-based bank account. Users can also use a filing partner where available. Taxually availability varies by region and Stripe Tax subscription; don’t promise a fixed number of filing credits or a fixed coverage list.
Testing considerations
Tax registrations in a sandbox are scoped to that sandbox. They don’t appear in live mode and must be re-created. Point the user to the Dashboard > Tax > Locations in live mode to add registrations before processing real payments.
Tax Settings are separate for sandboxes. Configure Tax Settings in each sandbox you use, and verify live-mode settings separately before processing real payments.
Add live-mode registrations before the first real transaction. If a transaction occurs with no active tax registration,
automatic_taxsilently collects 0 tax, with no error or warning.Sandbox transactions have no effect on threshold monitoring. Don’t infer live-mode threshold activity from sandbox activity.
If jurisdictions are unknown
Don’t guess which jurisdictions apply or add a registration without confirmation that the business is registered with the tax authority. Ask where the business sells, direct the user to their tax advisor when needed, then help them record confirmed registrations with the Tax Registrations API or the Dashboard.
If the region or tax type isn’t supported
Check the supported countries list. If the jurisdiction isn’t listed, tell the user:
Stripe Tax doesn’t support that region yet
They can collect tax manually using
tax_rateson the subscription or invoice instead (not alongsideautomatic_tax; you can’t use both)For unsupported tax types (customs duties, excise taxes), Stripe Tax doesn’t apply, so those are out of scope
Don’t attempt to approximate using a supported region as a proxy.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key, Needs Node.js
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Stripe
- Publisher
- Stripe (Official)
- Source
- stripe/ai · skills/stripe-best-practices · commit 38fa045
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- stripe/ai, stripe/ai, stripe/ai, stripe/ai, stripe/ai
AutoGineer is not affiliated with or endorsed by Stripe or Stripe.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download stripe-best-practices.zip