Skip to main content

Command Palette

Search for a command to run...

Global Payment Integration: Stripe, Alipay, SEPA, and WeChat Pay

Updated
8 min read

The payment method a user expects depends on their location — and offering the wrong ones dramatically reduces conversion. US users expect credit cards and PayPal. German users want SEPA Direct Debit and PayPal. Chinese users expect Alipay and WeChat Pay QR codes. This guide covers the global payment integration patterns used at tanstackship.com, supporting multiple payment methods across geographic markets.


Payment Methods by Market

Market Primary Methods % of Transactions Average Ticket
US/Canada Credit Card, PayPal Card: 79%, PayPal: 14% $49/mo
Europe Credit Card, PayPal, SEPA Card: 45%, PayPal: 25%, SEPA: 20% €39/mo
Germany SEPA, PayPal, Credit Card SEPA: 35%, PayPal: 30%, Card: 25% €35/mo
China Alipay, WeChat Pay Alipay: 55%, WeChat: 40% ¥149/mo
UK Credit Card, PayPal Card: 65%, PayPal: 25% £39/mo
Japan Credit Card, Konbini Card: 70%, Konbini: 15% ¥980/mo

Stripe Integration with Multiple Payment Methods

Setting Up Stripe Checkout with Payment Method Types

// server/billing/stripe.ts
import Stripe from "stripe"

const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
  apiVersion: "2025-02-24.acacia",
})

export const createCheckoutSession = createServerFn({ method: "POST" }).handler(
  async ({ data, context }: {
    data: { priceId: string; locale: string }
  }) => {
    // Determine payment methods based on locale
    const paymentMethods = getPaymentMethodsForLocale(data.locale)

    const session = await stripe.checkout.sessions.create({
      line_items: [{ price: data.priceId, quantity: 1 }],
      mode: "subscription",
      success_url: `https://tanstackship.com/${data.locale}/billing/success`,
      cancel_url: `https://tanstackship.com/${data.locale}/billing/cancel`,
      payment_method_types: paymentMethods,
      customer_creation: "always",
      locale: mapStripeLocale(data.locale),
      metadata: {
        locale: data.locale,
        userId: context.user.id,
      },
      ...(paymentMethods.includes("sepa_debit") && {
        payment_intent_data: {
          // SEPA requires mandate display
          mandate_data: {
            type: "online",
          },
        },
      }),
    })

    return { sessionId: session.id, url: session.url }
  }
)

function getPaymentMethodsForLocale(locale: string): string[] {
  const methods: Record<string, string[]> = {
    en: ["card", "paypal"],
    de: ["card", "paypal", "sepa_debit"],
    zh: ["card", "alipay", "wechat_pay"],
  }
  return methods[locale] ?? ["card"]
}

function mapStripeLocale(locale: string): Stripe.Checkout.SessionCreateParams.Locale {
  const locales: Record<string, Stripe.Checkout.SessionCreateParams.Locale> = {
    en: "auto",
    de: "de",
    zh: "zh",
  }
  return locales[locale] ?? "auto"
}

Managing Recurring Billing Globally

Price Configuration

// Define prices per market with appropriate currency
export const prices = {
  starter: {
    en: { price: 2900, currency: "usd" },                          // $29
    de: { price: 2900, currency: "eur" },                          // €29
    zh: { price: 12900, currency: "cny" },                         // ¥129
  },
  pro: {
    en: { price: 7900, currency: "usd" },                          // $79
    de: { price: 7900, currency: "eur" },                          // €79
    zh: { price: 34900, currency: "cny" },                         // ¥349
  },
}

// Create Stripe prices per currency
async function createPricesForLocale(locale: string) {
  const stripePrices = []

  for (const [plan, currencies] of Object.entries(prices)) {
    const { price, currency } = currencies[locale as keyof typeof currencies]

    const stripePrice = await stripe.prices.create({
      unit_amount: price,
      currency,
      recurring: { interval: "month" },
      product_data: {
        name: plan.charAt(0).toUpperCase() + plan.slice(1),
        metadata: { locale },
      },
    })

    stripePrices.push({ plan, stripePriceId: stripePrice.id })
  }

  return stripePrices
}

SEPA Direct Debit (German Market)

Mandate Collection Flow

export const createSepaSubscription = createServerFn({ method: "POST" }).handler(
  async ({ data, context }: { data: { priceId: string; iban: string } }) => {
    // 1. Create a Stripe customer
    const customer = await stripe.customers.create({
      email: context.user.email,
      metadata: { userId: context.user.id },
    })

    // 2. Create SEPA payment method
    const paymentMethod = await stripe.paymentMethods.create({
      type: "sepa_debit",
      sepa_debit: { iban: data.iban },
      billing_details: { email: context.user.email },
    })

    // 3. Attach payment method
    await stripe.paymentMethods.attach(paymentMethod.id, { customer: customer.id })

    // 4. Set as default
    await stripe.customers.update(customer.id, {
      invoice_settings: { default_payment_method: paymentMethod.id },
    })

    // 5. Create subscription
    const subscription = await stripe.subscriptions.create({
      customer: customer.id,
      items: [{ price: data.priceId }],
      default_payment_method: paymentMethod.id,
      payment_settings: {
        payment_method_types: ["sepa_debit"],
      },
    })

    return { subscriptionId: subscription.id }
  }
)

Alipay and WeChat Pay (Chinese Market)

QR Code Integration

export const createAlipaySession = createServerFn({ method: "POST" }).handler(
  async ({ data, context }: { data: { priceId: string } }) => {
    // Stripe Checkout handles Alipay/WeChat Pay QR code generation
    const session = await stripe.checkout.sessions.create({
      line_items: [{ price: data.priceId, quantity: 1 }],
      mode: "payment",
      payment_method_types: ["alipay", "wechat_pay"],
      success_url: `https://tanstackship.com/zh/billing/success`,
      cancel_url: `https://tanstackship.com/zh/billing/cancel`,
    })

    return {
      url: session.url,
      // Stripe Checkout shows QR code automatically on mobile
    }
  }
)

Tax Handling

Automatic Tax Calculation

export const createTaxAwareSession = createServerFn({ method: "POST" }).handler(
  async ({ data, context }: { data: { priceId: string; locale: string } }) => {
    // Stripe Tax automatically calculates VAT, GST, sales tax
    const session = await stripe.checkout.sessions.create({
      line_items: [{ price: data.priceId, quantity: 1 }],
      mode: "subscription",
      automatic_tax: { enabled: true },
      customer_update: { address: "auto" },
      // Billing address collected for tax calculation
      billing_address_collection: "required",
    })

    return { url: session.url }
  }
)

Tax Rates by Market

Country Tax Type Rate SaaS-Specific Notes
US Sales tax 0-10% (varies by state) Taxed in most states Origin-based for digital
Germany VAT (Umsatzsteuer) 19% Taxable Reverse charge for B2B
China VAT 6% (digital services) Taxable Withholding requirements
UK VAT 20% Taxable VAT MOSS scheme
Japan Consumption tax 10% Taxable Invoice system 2023+

Subscription Management

// Handle cross-market subscription changes
export const updateSubscriptionLocale = createServerFn({ method: "POST" }).handler(
  async ({ data, context }: {
    data: { subscriptionId: string; newLocale: string }
  }) => {
    const subscription = await stripe.subscriptions.retrieve(data.subscriptionId)

    // Update locale metadata
    await stripe.subscriptions.update(data.subscriptionId, {
      metadata: { locale: data.newLocale },
    })

    // If invoice locale changed, update default payment method
    if (data.newLocale === "de") {
      // Ensure SEPA mandate is active
    } else if (data.newLocale === "zh") {
      // Ensure Alipay/WeChat is available
    }

    return { updated: true }
  }
)

Failed Payment Recovery by Market

// Localized dunning emails based on user locale
async function handleFailedPayment(invoice: Stripe.Invoice) {
  const subscription = await stripe.subscriptions.retrieve(
    invoice.subscription as string
  )
  const locale = subscription.metadata.locale ?? "en"

  // Smart retry based on payment method
  if (subscription.metadata.payment_method === "sepa_debit") {
    // SEPA retries are handled by Stripe — wait 3-5 days
    await scheduleEmail(invoice.customer, "sepa_pending", locale)
  } else {
    // Credit card: immediate retry with smart timing
    await stripe.invoices.pay(invoice.id, {
      payment_method: invoice.payment_method as string,
    })
  }

  // Localize email template
  const emailTemplates = {
    en: "Your payment failed. Update your billing info here: {link}",
    de: "Ihre Zahlung ist fehlgeschlagen. Aktualisieren Sie hier: {link}",
    zh: "支付失败。点击此处更新账单信息:{link}",
  }

  await sendEmail({
    to: invoice.customer_email,
    subject: subjectTranslations[locale],
    body: emailTemplates[locale as keyof typeof emailTemplates].replace(
      "{link}",
      `https://tanstackship.com/${locale}/billing`
    ),
  })
}

Currency Display

function PriceDisplay({
  amount,
  locale,
  currency,
}: {
  amount: number
  locale: string
  currency: string
}) {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
  }).format(amount)
  // Result examples:
  // en, USD → "$29.99"
  // de, EUR → "29,99 €"
  // zh, CNY → "¥129.99"
}

Global Payment Integration Checklist

  • [ ] Payment methods configured per market (card + local methods)

  • [ ] Prices defined in local currencies

  • [ ] Tax calculation automated with Stripe Tax

  • [ ] Invoice and receipt localization (language, format, VAT ID)

  • [ ] Failed payment recovery emails localized

  • [ ] Refund policy complies with local laws (e.g., 14-day cancellation in EU)

  • [ ] Chargeback handling process documented per market

  • [ ] Currency conversion displayed clearly

  • [ ] Payment confirmation pages localized

  • [ ] Dunning email sequences translated

  • [ ] Subscription cancellation flows comply with local regulations


Conclusion

Global payment integration is one of the most impactful localization investments a SaaS can make. The principle is simple: let users pay the way they are accustomed to paying. A German user who sees SEPA Direct Debit as an option is significantly more likely to convert than one who sees only credit card.

Stripe's platform makes multi-method, multi-currency, multi-tax support manageable through a single API. Combined with locale-specific price configuration and localized payment flows, you can support global users without managing separate payment providers for each market.

For a production SaaS with global payment integration across US, European, and Chinese markets, see tanstackship.com.

Global Payment Integration: Stripe, Alipay, and WeChat Pay