# Payment Integration (Multiple Providers) **Meta-Description:** Payment Provider Integration. Stripe, PayPal, Klarna und lokale Zahlungsmethoden für globale E-Commerce Anwendungen. **Keywords:** Payment Integration, Stripe, PayPal, Klarna, Payment Gateway, Checkout, E-Commerce, Payment Methods --- ## Einführung **Globale E-Commerce** erfordert multiple Payment Provider. Kunden erwarten ihre bevorzugte Zahlungsmethode – von **Kreditkarte** über **PayPal** bis **Klarna**. Dieser Guide zeigt die Integration verschiedener Provider in einer einheitlichen Architektur. --- ## Payment Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ PAYMENT PROVIDER ABSTRACTION │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Unified Interface: │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ PaymentService │ │ │ │ ├── createPayment(order, method) │ │ │ │ ├── capturePayment(paymentId) │ │ │ │ ├── refundPayment(paymentId, amount) │ │ │ │ └── getPaymentStatus(paymentId) │ │ │ └─────────────────────────────────────────────────────┘ │ │ ↓ │ │ Provider Adapters: │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Stripe │ │ PayPal │ │ Klarna │ │ Local │ │ │ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ ↓ ↓ ↓ ↓ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Stripe │ │ PayPal │ │ Klarna │ │ SEPA/ │ │ │ │ API │ │ API │ │ API │ │ iDEAL/etc│ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ Payment Methods by Region: │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Germany: Klarna, SEPA, Giropay, Credit Card │ │ │ │ Netherlands: iDEAL, Credit Card, PayPal │ │ │ │ USA: Credit Card, PayPal, Apple Pay, Google Pay │ │ │ │ UK: Credit Card, PayPal, Klarna │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Payment Service Interface ```typescript // lib/payments/types.ts export interface PaymentMethod { id: string; type: PaymentMethodType; name: string; icon: string; countries: string[]; currencies: string[]; minAmount?: number; maxAmount?: number; } export type PaymentMethodType = | 'card' | 'paypal' | 'klarna' | 'sepa_debit' | 'ideal' | 'giropay' | 'sofort' | 'bancontact' | 'eps' | 'apple_pay' | 'google_pay'; export interface CreatePaymentInput { orderId: string; amount: number; currency: string; method: PaymentMethodType; customer: { email: string; name?: string; phone?: string; }; billing?: Address; shipping?: Address; metadata?: Record; returnUrl: string; cancelUrl?: string; } export interface PaymentResult { id: string; provider: string; status: PaymentStatus; redirectUrl?: string; clientSecret?: string; error?: string; } export type PaymentStatus = | 'pending' | 'processing' | 'requires_action' | 'succeeded' | 'failed' | 'canceled' | 'refunded'; export interface PaymentProvider { name: string; supportedMethods: PaymentMethodType[]; createPayment(input: CreatePaymentInput): Promise; capturePayment(paymentId: string): Promise; refundPayment(paymentId: string, amount?: number): Promise; getPaymentStatus(paymentId: string): Promise; handleWebhook(payload: unknown, signature: string): Promise; } ``` --- ## Stripe Adapter ```typescript // lib/payments/providers/stripe.ts import Stripe from 'stripe'; import { PaymentProvider, CreatePaymentInput, PaymentResult, PaymentStatus } from '../types'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-06-20' }); export class StripeProvider implements PaymentProvider { name = 'stripe'; supportedMethods: PaymentMethodType[] = [ 'card', 'sepa_debit', 'ideal', 'giropay', 'sofort', 'bancontact', 'eps', 'klarna' ]; async createPayment(input: CreatePaymentInput): Promise { try { // Map method to Stripe payment method type const paymentMethodTypes = this.mapPaymentMethod(input.method); const session = await stripe.checkout.sessions.create({ mode: 'payment', payment_method_types: paymentMethodTypes, customer_email: input.customer.email, line_items: [ { price_data: { currency: input.currency.toLowerCase(), unit_amount: input.amount, product_data: { name: `Order ${input.orderId}` } }, quantity: 1 } ], success_url: input.returnUrl, cancel_url: input.cancelUrl || input.returnUrl, metadata: { orderId: input.orderId, ...input.metadata } }); return { id: session.payment_intent as string, provider: 'stripe', status: 'pending', redirectUrl: session.url! }; } catch (error) { return { id: '', provider: 'stripe', status: 'failed', error: (error as Error).message }; } } async capturePayment(paymentId: string): Promise { const paymentIntent = await stripe.paymentIntents.capture(paymentId); return { id: paymentIntent.id, provider: 'stripe', status: this.mapStatus(paymentIntent.status) }; } async refundPayment(paymentId: string, amount?: number): Promise { const refund = await stripe.refunds.create({ payment_intent: paymentId, amount }); return { id: refund.id, provider: 'stripe', status: refund.status === 'succeeded' ? 'refunded' : 'pending' }; } async getPaymentStatus(paymentId: string): Promise { const paymentIntent = await stripe.paymentIntents.retrieve(paymentId); return this.mapStatus(paymentIntent.status); } async handleWebhook(payload: string, signature: string): Promise { const event = stripe.webhooks.constructEvent( payload, signature, process.env.STRIPE_WEBHOOK_SECRET! ); switch (event.type) { case 'payment_intent.succeeded': await this.handlePaymentSucceeded(event.data.object as Stripe.PaymentIntent); break; case 'payment_intent.payment_failed': await this.handlePaymentFailed(event.data.object as Stripe.PaymentIntent); break; } } private mapPaymentMethod(method: PaymentMethodType): Stripe.Checkout.SessionCreateParams.PaymentMethodType[] { const mapping: Record = { card: ['card'], sepa_debit: ['sepa_debit'], ideal: ['ideal'], giropay: ['giropay'], sofort: ['sofort'], bancontact: ['bancontact'], eps: ['eps'], klarna: ['klarna'], paypal: ['paypal'], apple_pay: ['card'], google_pay: ['card'] }; return mapping[method] || ['card']; } private mapStatus(status: Stripe.PaymentIntent.Status): PaymentStatus { const mapping: Record = { requires_payment_method: 'pending', requires_confirmation: 'pending', requires_action: 'requires_action', processing: 'processing', requires_capture: 'processing', canceled: 'canceled', succeeded: 'succeeded' }; return mapping[status] || 'pending'; } } ``` --- ## PayPal Adapter ```typescript // lib/payments/providers/paypal.ts import { PaymentProvider, CreatePaymentInput, PaymentResult } from '../types'; const PAYPAL_API = process.env.PAYPAL_MODE === 'live' ? 'https://api-m.paypal.com' : 'https://api-m.sandbox.paypal.com'; export class PayPalProvider implements PaymentProvider { name = 'paypal'; supportedMethods: PaymentMethodType[] = ['paypal']; private async getAccessToken(): Promise { const auth = Buffer.from( `${process.env.PAYPAL_CLIENT_ID}:${process.env.PAYPAL_SECRET}` ).toString('base64'); const response = await fetch(`${PAYPAL_API}/v1/oauth2/token`, { method: 'POST', headers: { 'Authorization': `Basic ${auth}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'grant_type=client_credentials' }); const data = await response.json(); return data.access_token; } async createPayment(input: CreatePaymentInput): Promise { const accessToken = await this.getAccessToken(); const response = await fetch(`${PAYPAL_API}/v2/checkout/orders`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ intent: 'CAPTURE', purchase_units: [ { reference_id: input.orderId, amount: { currency_code: input.currency.toUpperCase(), value: (input.amount / 100).toFixed(2) } } ], application_context: { return_url: input.returnUrl, cancel_url: input.cancelUrl || input.returnUrl, brand_name: 'Your Store', user_action: 'PAY_NOW' } }) }); const order = await response.json(); if (order.error) { return { id: '', provider: 'paypal', status: 'failed', error: order.error.message }; } const approveLink = order.links.find((l: any) => l.rel === 'approve'); return { id: order.id, provider: 'paypal', status: 'pending', redirectUrl: approveLink?.href }; } async capturePayment(paymentId: string): Promise { const accessToken = await this.getAccessToken(); const response = await fetch( `${PAYPAL_API}/v2/checkout/orders/${paymentId}/capture`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } } ); const result = await response.json(); return { id: result.id, provider: 'paypal', status: result.status === 'COMPLETED' ? 'succeeded' : 'failed' }; } async refundPayment(paymentId: string, amount?: number): Promise { const accessToken = await this.getAccessToken(); // Get capture ID from order const orderResponse = await fetch( `${PAYPAL_API}/v2/checkout/orders/${paymentId}`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const order = await orderResponse.json(); const captureId = order.purchase_units[0]?.payments?.captures?.[0]?.id; if (!captureId) { return { id: '', provider: 'paypal', status: 'failed', error: 'No capture found' }; } const refundResponse = await fetch( `${PAYPAL_API}/v2/payments/captures/${captureId}/refund`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: amount ? JSON.stringify({ amount: { value: (amount / 100).toFixed(2), currency_code: order.purchase_units[0].amount.currency_code } }) : undefined } ); const refund = await refundResponse.json(); return { id: refund.id, provider: 'paypal', status: refund.status === 'COMPLETED' ? 'refunded' : 'pending' }; } async getPaymentStatus(paymentId: string): Promise { const accessToken = await this.getAccessToken(); const response = await fetch( `${PAYPAL_API}/v2/checkout/orders/${paymentId}`, { headers: { 'Authorization': `Bearer ${accessToken}` } } ); const order = await response.json(); const statusMap: Record = { CREATED: 'pending', SAVED: 'pending', APPROVED: 'requires_action', COMPLETED: 'succeeded', VOIDED: 'canceled' }; return statusMap[order.status] || 'pending'; } async handleWebhook(payload: unknown, signature: string): Promise { // Verify webhook signature // Process webhook events } } ``` --- ## Payment Service ```typescript // lib/payments/service.ts import { StripeProvider } from './providers/stripe'; import { PayPalProvider } from './providers/paypal'; import { PaymentProvider, CreatePaymentInput, PaymentResult, PaymentMethodType } from './types'; import { db } from '@/lib/db'; const providers: Record = { stripe: new StripeProvider(), paypal: new PayPalProvider() }; function getProviderForMethod(method: PaymentMethodType): PaymentProvider { for (const provider of Object.values(providers)) { if (provider.supportedMethods.includes(method)) { return provider; } } throw new Error(`No provider supports payment method: ${method}`); } export async function createPayment(input: CreatePaymentInput): Promise { const provider = getProviderForMethod(input.method); const result = await provider.createPayment(input); // Store payment record await db.payment.create({ data: { id: result.id, orderId: input.orderId, provider: provider.name, method: input.method, amount: input.amount, currency: input.currency, status: result.status, metadata: input.metadata } }); return result; } export async function capturePayment(paymentId: string): Promise { const payment = await db.payment.findUnique({ where: { id: paymentId } }); if (!payment) throw new Error('Payment not found'); const provider = providers[payment.provider]; const result = await provider.capturePayment(paymentId); await db.payment.update({ where: { id: paymentId }, data: { status: result.status } }); return result; } export async function refundPayment( paymentId: string, amount?: number ): Promise { const payment = await db.payment.findUnique({ where: { id: paymentId } }); if (!payment) throw new Error('Payment not found'); const provider = providers[payment.provider]; const result = await provider.refundPayment(paymentId, amount); await db.payment.update({ where: { id: paymentId }, data: { status: result.status, refundedAmount: amount || payment.amount } }); return result; } export function getAvailablePaymentMethods( country: string, currency: string, amount: number ): PaymentMethod[] { const methods: PaymentMethod[] = [ { id: 'card', type: 'card', name: 'Credit/Debit Card', icon: '/icons/card.svg', countries: ['*'], currencies: ['*'] }, { id: 'paypal', type: 'paypal', name: 'PayPal', icon: '/icons/paypal.svg', countries: ['*'], currencies: ['EUR', 'USD', 'GBP'] }, { id: 'klarna', type: 'klarna', name: 'Klarna', icon: '/icons/klarna.svg', countries: ['DE', 'AT', 'NL', 'SE', 'FI', 'NO', 'DK', 'GB', 'US'], currencies: ['EUR', 'USD', 'GBP', 'SEK', 'NOK', 'DKK'], minAmount: 100, maxAmount: 500000 }, { id: 'ideal', type: 'ideal', name: 'iDEAL', icon: '/icons/ideal.svg', countries: ['NL'], currencies: ['EUR'] }, { id: 'giropay', type: 'giropay', name: 'Giropay', icon: '/icons/giropay.svg', countries: ['DE'], currencies: ['EUR'] }, { id: 'sepa_debit', type: 'sepa_debit', name: 'SEPA Direct Debit', icon: '/icons/sepa.svg', countries: ['DE', 'AT', 'NL', 'BE', 'FR', 'ES', 'IT'], currencies: ['EUR'] } ]; return methods.filter(method => { const countryMatch = method.countries.includes('*') || method.countries.includes(country); const currencyMatch = method.currencies.includes('*') || method.currencies.includes(currency); const amountMatch = (!method.minAmount || amount >= method.minAmount) && (!method.maxAmount || amount <= method.maxAmount); return countryMatch && currencyMatch && amountMatch; }); } ``` --- ## Checkout UI ```tsx // components/checkout/PaymentMethodSelector.tsx 'use client'; import { useState } from 'react'; import Image from 'next/image'; import { PaymentMethod } from '@/lib/payments/types'; interface Props { methods: PaymentMethod[]; selected: string | null; onSelect: (methodId: string) => void; } export function PaymentMethodSelector({ methods, selected, onSelect }: Props) { return (

Payment Method

{methods.map((method) => ( ))}
); } ``` --- ## Provider Comparison | Provider | Card | PayPal | Klarna | Local Methods | Fees | |----------|------|--------|--------|---------------|------| | **Stripe** | ✓ | ✓ | ✓ | iDEAL, SEPA, etc. | 1.4%+ | | **PayPal** | ✓ | ✓ | - | - | 2.9%+ | | **Adyen** | ✓ | ✓ | ✓ | 250+ methods | Custom | | **Mollie** | ✓ | ✓ | ✓ | iDEAL, Bancontact | 1.8%+ | --- ## Fazit Payment Integration erfordert: 1. **Abstraction Layer**: Einheitliches Interface 2. **Multiple Providers**: Regionale Methoden 3. **Error Handling**: Graceful Degradation 4. **Webhooks**: Asynchrone Statusupdates Die richtige Payment-Strategie erhöht Conversion. --- ## Bildprompts 1. "Payment method selection UI, card icons and options" 2. "Checkout flow diagram, multiple payment providers" 3. "Payment dashboard, transaction history and analytics" --- ## Quellen - [Stripe Payment Methods](https://stripe.com/docs/payments/payment-methods) - [PayPal Checkout](https://developer.paypal.com/docs/checkout/) - [Klarna Integration](https://docs.klarna.com/) - [Payment Provider Comparison](https://www.merchantmaverick.com/)