Handle multiple currencies in Stripe by specifying the currency code (lowercase ISO 4217) when creating PaymentIntents or Checkout Sessions. Stripe settles to your default currency at the current exchange rate. Use Adaptive Pricing for automatic localized pricing in Checkout, or create separate Price objects per currency for fixed international pricing.
Multi-Currency Payments with Stripe
Stripe supports 135+ currencies. When you create a PaymentIntent, you specify the presentment currency — what the customer sees and pays. Stripe converts to your settlement currency (the currency of your bank account) at the current exchange rate, charging a 1% conversion fee on top of standard processing fees. For Stripe Checkout, Adaptive Pricing can auto-convert prices to the customer's local currency. Alternatively, create separate Price objects for each currency for fixed rates.
Prerequisites
- A Stripe account with your settlement currency configured
- Node.js 18+ with the stripe npm package
- Understanding of ISO 4217 currency codes (usd, eur, gbp, jpy, etc.)
Step-by-step guide
Create a PaymentIntent in a specific currency
Create a PaymentIntent in a specific currency
Specify the currency parameter as a lowercase ISO 4217 code. The amount is in the smallest unit of that currency.
1// Charge €25.00 (EUR)2const paymentIntentEUR = await stripe.paymentIntents.create({3 amount: 2500, // 2500 cents = €25.004 currency: 'eur',5 automatic_payment_methods: { enabled: true },6});78// Charge £15.00 (GBP)9const paymentIntentGBP = await stripe.paymentIntents.create({10 amount: 1500, // 1500 pence = £15.0011 currency: 'gbp',12 automatic_payment_methods: { enabled: true },13});1415// Charge ¥3000 (JPY — zero-decimal currency)16const paymentIntentJPY = await stripe.paymentIntents.create({17 amount: 3000, // 3000 yen (no cents)18 currency: 'jpy',19 automatic_payment_methods: { enabled: true },20});Expected result: PaymentIntents are created in EUR, GBP, and JPY. Stripe converts to your settlement currency at the current exchange rate.
Use dynamic currency in Checkout Sessions
Use dynamic currency in Checkout Sessions
Pass the customer's preferred currency to your Checkout Session endpoint. Stripe displays the price in that currency.
1app.post('/create-checkout-session', async (req, res) => {2 const { currency = 'usd', amount } = req.body;34 const session = await stripe.checkout.sessions.create({5 mode: 'payment',6 line_items: [7 {8 price_data: {9 currency: currency.toLowerCase(),10 product_data: { name: 'Premium Widget' },11 unit_amount: amount, // In smallest unit of currency12 },13 quantity: 1,14 },15 ],16 success_url: 'https://yoursite.com/success',17 cancel_url: 'https://yoursite.com/cancel',18 });1920 res.json({ url: session.url });21});Expected result: The Checkout page displays the price in the specified currency with the correct symbol and format.
Enable Adaptive Pricing for automatic conversion
Enable Adaptive Pricing for automatic conversion
Stripe's Adaptive Pricing (for Checkout and Payment Links) automatically shows prices in the customer's local currency based on their location. Enable it in your Dashboard or when creating Prices.
1// Create a Price with Adaptive Pricing enabled2const price = await stripe.prices.create({3 product: 'prod_xxx',4 unit_amount: 2000, // Base price: $20.00 USD5 currency: 'usd',6 currency_options: {7 eur: { unit_amount: 1850 }, // Fixed: €18.508 gbp: { unit_amount: 1600 }, // Fixed: £16.009 },10});1112// Or use the Price in a Checkout Session13const session = await stripe.checkout.sessions.create({14 mode: 'payment',15 line_items: [{ price: price.id, quantity: 1 }],16 // Stripe auto-selects currency based on customer location17 success_url: 'https://yoursite.com/success',18 cancel_url: 'https://yoursite.com/cancel',19});Expected result: Customers in Europe see EUR pricing, UK customers see GBP, and others see USD or their local equivalent.
Handle zero-decimal currencies correctly
Handle zero-decimal currencies correctly
Some currencies like JPY, KRW, VND don't have sub-units (cents). The amount value IS the full amount. Build a helper to handle this.
1const ZERO_DECIMAL_CURRENCIES = [2 'bif', 'clp', 'djf', 'gnf', 'jpy', 'kmf', 'krw', 'mga',3 'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf',4];56function toStripeAmount(dollarAmount, currency) {7 if (ZERO_DECIMAL_CURRENCIES.includes(currency.toLowerCase())) {8 return Math.round(dollarAmount); // No multiplication needed9 }10 return Math.round(dollarAmount * 100); // Convert to cents11}1213// Usage:14toStripeAmount(20, 'usd'); // 2000 (cents)15toStripeAmount(3000, 'jpy'); // 3000 (yen)Expected result: The helper correctly converts display amounts to Stripe amounts for both regular and zero-decimal currencies.
Complete working example
1const express = require('express');2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34const app = express();5app.use(express.json());67const ZERO_DECIMAL_CURRENCIES = [8 'bif', 'clp', 'djf', 'gnf', 'jpy', 'kmf', 'krw', 'mga',9 'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf',10];1112function toSmallestUnit(amount, currency) {13 const cur = currency.toLowerCase();14 if (ZERO_DECIMAL_CURRENCIES.includes(cur)) {15 return Math.round(amount);16 }17 return Math.round(amount * 100);18}1920function fromSmallestUnit(amount, currency) {21 const cur = currency.toLowerCase();22 if (ZERO_DECIMAL_CURRENCIES.includes(cur)) {23 return amount;24 }25 return amount / 100;26}2728// Multi-currency checkout29app.post('/create-checkout-session', async (req, res) => {30 const { displayAmount, currency = 'usd', productName = 'Widget' } = req.body;3132 try {33 const session = await stripe.checkout.sessions.create({34 mode: 'payment',35 line_items: [36 {37 price_data: {38 currency: currency.toLowerCase(),39 product_data: { name: productName },40 unit_amount: toSmallestUnit(displayAmount, currency),41 },42 quantity: 1,43 },44 ],45 success_url: `${req.headers.origin}/success?session_id={CHECKOUT_SESSION_ID}`,46 cancel_url: `${req.headers.origin}/cancel`,47 });4849 res.json({ url: session.url });50 } catch (err) {51 res.status(500).json({ error: err.message });52 }53});5455// Multi-currency PaymentIntent56app.post('/create-payment-intent', async (req, res) => {57 const { displayAmount, currency = 'usd' } = req.body;5859 try {60 const paymentIntent = await stripe.paymentIntents.create({61 amount: toSmallestUnit(displayAmount, currency),62 currency: currency.toLowerCase(),63 automatic_payment_methods: { enabled: true },64 });6566 res.json({ clientSecret: paymentIntent.client_secret });67 } catch (err) {68 res.status(500).json({ error: err.message });69 }70});7172app.listen(4000, () => console.log('Multi-currency server on port 4000'));Common mistakes when handling multiple currencies in Stripe
Why it's a problem: Treating zero-decimal currencies like regular currencies
How to avoid: For JPY, KRW, VND, and other zero-decimal currencies, the amount IS the full amount. Passing 2000 for JPY means ¥2,000 — not ¥20.00. Use a helper function to handle conversion.
Why it's a problem: Assuming settlement happens in the presentment currency
How to avoid: Stripe converts to your settlement currency (your bank account's currency) at the current rate. A €25 charge settles in USD if your bank is USD. Stripe charges 1% for currency conversion.
Why it's a problem: Hardcoding prices without considering exchange rates
How to avoid: If you set EUR prices as a simple conversion of USD, exchange rates will drift. Either use Adaptive Pricing or regularly update your currency_options with current rates.
Why it's a problem: Using uppercase currency codes
How to avoid: Stripe requires lowercase ISO 4217 codes: 'usd', not 'USD'. Always .toLowerCase() the currency before passing to Stripe.
Best practices
- Always use lowercase ISO 4217 currency codes (usd, eur, gbp, jpy)
- Build a helper function that handles zero-decimal currency conversion
- Use Adaptive Pricing in Checkout for automatic localized pricing
- Create fixed currency_options on Prices for markets where you want specific pricing
- Account for Stripe's 1% currency conversion fee in your pricing
- Test with multiple currencies using card 4242 4242 4242 4242 in test mode
- Display the correct currency symbol on your frontend using Intl.NumberFormat
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write a Node.js Express server that creates Stripe PaymentIntents in multiple currencies. Include a helper function for zero-decimal currencies (JPY, KRW). Accept the currency and display amount from the request body and convert to Stripe's smallest unit format.
Add multi-currency support to my Stripe checkout. Accept a currency parameter (usd, eur, gbp, jpy) from the frontend, correctly handle zero-decimal currencies, and create the Checkout Session in the specified currency.
Frequently asked questions
How many currencies does Stripe support?
Stripe supports 135+ currencies for payment processing. The exact list depends on your country and payment methods. Check your Dashboard → Settings → Payment methods to see which currencies are enabled.
What is the currency conversion fee?
Stripe charges a 1% fee on top of the standard processing fee when the presentment currency differs from your settlement currency. For example, if you charge in EUR but settle in USD, there's an extra 1% fee.
Can I settle in multiple currencies?
Yes, if you add bank accounts in different currencies. For example, add a EUR bank account to settle EUR charges directly without conversion. Go to Settings → Bank accounts and scheduling.
What are zero-decimal currencies?
Currencies like JPY, KRW, and VND don't have sub-units (cents). For JPY, amount: 5000 means ¥5,000. For USD, amount: 5000 means $50.00. Always check if a currency is zero-decimal before converting.
Can RapidDev help with international payment setup?
Yes. RapidDev helps businesses set up multi-currency payment systems including localized pricing tables, automatic currency detection, exchange rate management, and multi-region settlement optimization.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation