Stripe returns a currency mismatch error when you try to charge a customer or pay an invoice in a different currency than the one specified on the object. This commonly happens when creating a PaymentIntent without specifying a currency, using a price in one currency but charging in another, or mixing currencies within a single customer. Always pass the currency parameter explicitly and keep it consistent.
Why Currency Mismatch Errors Happen in Stripe
Stripe requires consistent currency usage across related objects. If you create a price in EUR but try to create a PaymentIntent in USD for that price, Stripe rejects it. Similarly, a customer's default currency (set by their first charge) may conflict with subsequent charges in different currencies. The fix is straightforward: always explicitly specify the currency parameter and ensure it matches across your prices, invoices, and payment intents.
Prerequisites
- A Stripe account in test mode
- Node.js 18+ with the Stripe npm package
- At least one product and price created in the Stripe Dashboard
Step-by-step guide
Understand how Stripe assigns currencies
Understand how Stripe assigns currencies
Every Stripe price has a fixed currency set at creation. When you create a PaymentIntent, you must specify a currency. If these don't match — for example, a USD price charged in EUR — Stripe returns a currency mismatch error. Amounts are always in the smallest currency unit (cents for USD, pennies for GBP).
Expected result: You understand that currencies are set at the price level and must be consistent across all related Stripe objects.
Always pass the currency parameter explicitly
Always pass the currency parameter explicitly
Never rely on defaults. Explicitly set the currency when creating PaymentIntents, charges, or invoices. This prevents surprises when your account's default currency differs from what you intend.
1// CORRECT — explicit currency2const paymentIntent = await stripe.paymentIntents.create({3 amount: 2000, // $20.00 in cents4 currency: 'usd', // Always specify!5 automatic_payment_methods: { enabled: true },6});78// WRONG — missing currency leads to account default9const paymentIntent = await stripe.paymentIntents.create({10 amount: 2000,11 // currency not specified — uses account default, which may not be what you want12});Expected result: PaymentIntents are created with an explicit currency that matches your prices.
Match the currency to your Stripe price
Match the currency to your Stripe price
When charging for a specific product, retrieve the price first and use its currency to create the PaymentIntent. This ensures the amounts and currency are always in sync.
1async function createPaymentForPrice(priceId) {2 // Fetch the price to get its currency and unit_amount3 const price = await stripe.prices.retrieve(priceId);45 const paymentIntent = await stripe.paymentIntents.create({6 amount: price.unit_amount, // Use the price's amount7 currency: price.currency, // Use the price's currency8 metadata: { price_id: priceId },9 automatic_payment_methods: { enabled: true },10 });1112 return paymentIntent;13}Expected result: The PaymentIntent currency always matches the price currency, eliminating mismatch errors.
Handle multi-currency products
Handle multi-currency products
If you sell in multiple currencies, create separate prices for each currency on the same product. Then select the correct price based on the customer's currency preference.
1// Create prices for different currencies on the same product2const usdPrice = await stripe.prices.create({3 product: 'prod_ABC123',4 unit_amount: 2000, // $20.005 currency: 'usd',6});78const eurPrice = await stripe.prices.create({9 product: 'prod_ABC123',10 unit_amount: 1800, // 18.00 EUR11 currency: 'eur',12});1314// Select the right price based on customer's currency15function getPriceForCurrency(currency) {16 const priceMap = {17 usd: 'price_usd_id',18 eur: 'price_eur_id',19 };20 return priceMap[currency] || priceMap.usd;21}Expected result: Each currency has its own price object, and you select the correct one based on the customer's preference.
Complete working example
1require('dotenv').config();2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34// Supported currencies and their price IDs5const PRICE_MAP = {6 usd: process.env.PRICE_USD,7 eur: process.env.PRICE_EUR,8 gbp: process.env.PRICE_GBP,9};1011const SUPPORTED_CURRENCIES = Object.keys(PRICE_MAP);1213async function createPaymentIntent(currency, priceId) {14 // Validate currency15 const normalizedCurrency = currency.toLowerCase();16 if (!SUPPORTED_CURRENCIES.includes(normalizedCurrency)) {17 throw new Error(18 `Unsupported currency: ${currency}. Supported: ${SUPPORTED_CURRENCIES.join(', ')}`19 );20 }2122 // Fetch price to ensure currency matches23 const price = await stripe.prices.retrieve(priceId || PRICE_MAP[normalizedCurrency]);2425 if (price.currency !== normalizedCurrency) {26 throw new Error(27 `Currency mismatch: price is in ${price.currency} but ${normalizedCurrency} was requested`28 );29 }3031 const paymentIntent = await stripe.paymentIntents.create({32 amount: price.unit_amount,33 currency: price.currency,34 metadata: {35 price_id: price.id,36 product_id: price.product,37 },38 automatic_payment_methods: { enabled: true },39 });4041 return paymentIntent;42}4344module.exports = { createPaymentIntent, SUPPORTED_CURRENCIES };Common mistakes when fixing currency mismatch error in Stripe
Why it's a problem: Omitting the currency parameter and relying on account defaults
How to avoid: Always explicitly pass the currency parameter when creating PaymentIntents, charges, or invoice items. Account defaults may not match your intended currency.
Why it's a problem: Using a price in one currency and creating a PaymentIntent in another
How to avoid: Retrieve the price first and use price.currency for the PaymentIntent. Or create separate prices for each currency you support.
Why it's a problem: Passing amounts in dollars instead of cents
How to avoid: Stripe uses the smallest currency unit. For USD, pass 2000 for $20.00. For JPY (zero-decimal currency), pass 2000 for 2000 yen.
Why it's a problem: Mixing currencies on a single subscription
How to avoid: All items in a subscription must use the same currency. Create separate subscriptions if a customer needs products in different currencies.
Best practices
- Always pass the currency parameter explicitly — never rely on defaults
- Retrieve the price object and use its currency when creating PaymentIntents
- Create separate price objects for each currency you support
- Use lowercase three-letter ISO currency codes (usd, eur, gbp)
- Remember that Stripe uses smallest currency units — cents for USD, yen for JPY
- Validate the currency on your server before calling the Stripe API
- Store the customer's preferred currency in your database for consistent billing
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write a Node.js function that creates a Stripe PaymentIntent with proper currency handling. The function should accept a currency code, retrieve the matching price from a currency-to-price mapping, validate the currency matches, and create the PaymentIntent with explicit currency. Handle currency mismatches with clear error messages.
Build a multi-currency Stripe payment handler in Node.js that maps currencies to price IDs, validates currency consistency between prices and PaymentIntents, and returns clear errors for mismatches. Include support for USD, EUR, and GBP.
Frequently asked questions
What is a zero-decimal currency in Stripe?
Zero-decimal currencies like JPY (Japanese yen) don't use fractional units. For JPY, pass the full amount: 1000 means 1000 yen. For USD (two-decimal), pass 1000 to mean $10.00. Stripe documentation lists all zero-decimal currencies.
Can I change the currency of an existing Stripe price?
No. Prices are immutable once created. To use a different currency, create a new price on the same product with the desired currency.
What happens if I don't specify a currency on a PaymentIntent?
Stripe requires the currency parameter on PaymentIntents. If omitted, the API returns an error. Always pass it explicitly.
Can a single Stripe customer have charges in multiple currencies?
Yes, but each charge or subscription must use a single consistent currency. A customer's default currency is set by their first charge, but you can charge them in different currencies for separate transactions.
How do I handle currency conversion?
Stripe does not convert currencies automatically. If you need to display prices in the customer's local currency, use a separate exchange rate service and create Stripe prices for each supported currency.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation