Skip to main content

Payment Integration - Stripe & Klarna

The Reachu Swift SDK includes production-ready integrationswith Stripe and Klarna payment processors. Handle credit cards, digital wallets, and buy-now-pay-later options seamlessly.

Zero Configuration Required!

**NEW:**Stripe is now automatically initializedby the SDK! Just call ConfigurationLoader.loadConfiguration() and payments work out of the box. No manual setup, no publishable keys to configure, no boilerplate code.

Overview

Supported Payment Methods: - Stripe - Credit/debit cards, Apple Pay, Google Pay (auto-configured!)

  • Klarna - Buy now, pay later (installments)
  • More coming soon - PayPal, Vipps, and more

What's Automatic: - Stripe publishable key fetched from Reachu API

  • Fallback to test key for development
  • Platform-aware initialization (iOS only)
  • Error handling and retries
  • Zero boilerplate code in your app

Prerequisites

Stripe Setup

**Good news!**Stripe is automatically configuredby the SDK. You only need to add the dependency:

  1. Add Stripe SDK
Package.swift
 dependencies: [
.package(url: "https://github.com/stripe/stripe-ios.git", from: "23.0.0")
]

  1. That's it! - The SDK automatically fetches your Stripe publishable key from Reachu API
  • No manual configuration needed
  • Works out of the box when you call ConfigurationLoader.loadConfiguration()
Automatic Initialization

The SDK handles Stripe initialization automatically:

  • Fetches publishable key from Reachu API
  • Falls back to test key if API is unavailable
  • Only runs on iOS platform
  • Zero configuration required from your side

Optional: Apple Pay Configuration

If you want to enable Apple Pay, add to your reachu-config.json:

reachu-config.json
{
"payment": {
"applePay": {
"merchantIdentifier": "merchant.com.yourapp"
}
}
}

Klarna Setup

  1. Klarna Account - Contact Klarna for merchant account
  • Get your Client Token
  1. Configure in Reachu
reachu-config.json
 {
"payment": {
"klarna": {
"clientToken": "YOUR_KLARNA_CLIENT_TOKEN"
}
}
}

Stripe Integration

Automatic Setup (Zero Configuration!)

The SDK initializes Stripe automaticallywhen you call ConfigurationLoader.loadConfiguration():

YourApp.swift
import SwiftUI
import ReachuCore
import ReachuUI

@main
struct YourApp: App {
@StateObject private var cartManager = CartManager()
@StateObject private var checkoutDraft = CheckoutDraft()

init() {
// This automatically initializes Stripe!
ConfigurationLoader.loadConfiguration()
}

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(cartManager)
.environmentObject(checkoutDraft)
}
}
}

**That's it!**The SDK handles:

  • Fetching Stripe publishable key from Reachu API
  • Configuring StripeAPI.defaultPublishableKey
  • Falling back to test key if needed
  • Platform checks (iOS only)

Using Stripe in Checkout

Simply show the checkout overlay - Stripe is already configured:

ContentView.swift
import SwiftUI
import ReachuUI

struct ContentView: View {
@EnvironmentObject private var cartManager: CartManager
@EnvironmentObject private var checkoutDraft: CheckoutDraft

var body: some View {
MyAppContent()
// Stripe Payment Sheet works automatically
.sheet(isPresented: $cartManager.isCheckoutPresented) {
RCheckoutOverlay()
.environmentObject(cartManager)
.environmentObject(checkoutDraft)
}
}
}

Payment Flow

  1. User Reviews CartRCheckoutOverlay shows order summary
  2. Enters Shipping AddressCheckoutDraft normalizes data
  3. Selects Stripe Payment → SDK initializes Payment Sheet
  4. Completes Payment → Stripe processes securely
  5. Confirmation → Order confirmed, cart cleared

Stripe Payment Sheet Features

Automatically includes: - Credit/Debit card input with validation

  • Apple Pay (if configured)
  • Google Pay (on Android)
  • Card saving for future purchases
  • 3D Secure authentication
  • Error handling and retry logic

Dynamic Payment Methods

Payment methods are completely dynamic - controlled from your Reachu dashboard:

reachu-config.json
{
"cart": {
"enableGuestCheckout": true,
"requirePhoneNumber": true,
"defaultShippingCountry": "US",
"supportedPaymentMethods": ["stripe", "klarna", "vipps", "paypal"]
}
}

Reachu API Controls Everything

The SDK fetches available payment methods from Reachu API in real-time:

  • API is the source of truth - Shows what Reachu backend returns
  • Enable/disable from dashboard - Changes appear immediately in apps
  • No app rebuild needed - Methods update automatically
  • Config is fallback only - Used only if API is unreachable

**How it works:**1. User opens checkout → SDK calls payment.getAvailableMethods() 2. API returns enabled methods: [{name: "Stripe"}, {name: "Klarna"}, {name: "Vipps"}] 3. SDK displays all returned methods with official logos 4. If API fails → Falls back to supportedPaymentMethods from config 5. Payment logos loaded automatically from SDK resources

Supported payment providers with official branding: - Stripe - Blue Stripe logo

  • Klarna - Pink Klarna logo
  • Vipps - Orange Vipps logo (Norway)
  • PayPal - Coming soon

Klarna Integration

Basic Implementation

Klarna integration uses WebView for the payment flow:

RCheckoutOverlay.swift
// Klarna is automatically handled in RCheckoutOverlay
// Users see the Klarna WebView when selecting Klarna payment

Payment Methods Available:
- "Pay in 30 days"
- "Pay in 3 installments"
- "Pay in 4 installments"
- "Slice it" (flexible payments)

Klarna Payment Flow

  1. User Selects Klarna → SDK requests payment session
  2. Klarna WebView Opens → User logs in to Klarna
  3. Selects Payment Plan → "Pay in 3" or "Pay in 30 days"
  4. Authorizes Payment → Klarna approves transaction
  5. Confirmation → Returns to app, order confirmed

Klarna WebView

The SDK includes two Klarna WebView options:

Option 1: HTML Content

KlarnaWebViewHTML(
html: klarnaHTML,
successURLPrefix: "https://yourapp.com/success"
) { result in
switch result {
case .success:
// Payment completed
case .canceled:
// User canceled
case .error(let error):
// Handle error
}
}

Option 2: Start URL

KlarnaWebView(
startURL: klarnaURL,
successURLPrefix: "https://yourapp.com/success",
cancelURLPrefix: "https://yourapp.com/cancel"
) { result in
// Handle result
}

RCheckoutOverlay Payment Handling

The RCheckoutOverlay component manages the complete payment flow:

Multi-Step Checkout

public enum CheckoutStep {
case address // Collect shipping address
case orderSummary // Review cart and select shipping
case review // Final review and payment selection
case success // Order confirmation
case error // Error handling
}

Payment Method Selection

public enum PaymentMethod: String, CaseIterable {
case stripe = "stripe"
case klarna = "klarna"

var displayName: String {
switch self {
case .stripe: return "Credit Card"
case .klarna: return "Pay with Klarna"
}
}

var supportsInstallments: Bool {
self == .klarna
}
}

Shipping Options

public enum ShippingOption: String, CaseIterable {
case standard = "standard"
case express = "express"

var price: Double {
switch self {
case .standard: return 0.0
case .express: return 9.99
}
}
}

Complete Payment Flow Example

CheckoutView.swift
import SwiftUI
import ReachuUI
import ReachuCore

struct CheckoutView: View {
@EnvironmentObject private var cartManager: CartManager
@EnvironmentObject private var checkoutDraft: CheckoutDraft
@State private var isProcessing = false

var body: some View {
VStack {
// Cart Summary
CartSummaryView()

// Checkout Button
Button(action: startCheckout) {
Text("Proceed to Checkout")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(12)
}
.disabled(cartManager.items.isEmpty || isProcessing)
}
.sheet(isPresented: $cartManager.isCheckoutPresented) {
RCheckoutOverlay()
.environmentObject(cartManager)
.environmentObject(checkoutDraft)
}
}

private func startCheckout() {
guard !cartManager.items.isEmpty else { return }

// Pre-fill checkout data if available
if let user = UserSession.current {
checkoutDraft.email = user.email
checkoutDraft.firstName = user.firstName
checkoutDraft.lastName = user.lastName
}

// Show checkout overlay
cartManager.showCheckout()
}
}

Checkout Validations

The SDK includes comprehensive validation to ensure smooth checkout:

Address Validation

  • All required fields highlighted with subtle primary color border when empty
  • Specific validation messages: "Please enter your email address"
  • Real-time visual feedback as user types
  • Button disabled until all fields complete

Shipping Validation

  • Must select shipping method for all products
  • Items without shipping highlighted with primary color border
  • "Required" badge shown on Shipping Options section
  • Clear validation message above disabled button
  • Cannot proceed without selecting shipping

Visual Feedback

ℹ Please select shipping method for all items
(Subtle primary color background with border)

[ Initiate Payment ] ← Disabled until valid

Cart Management

Smart Quantity Controls

The SDK includes intelligent quantity management:

Quantity Behavior:

Quantity > 1: [ - ] 2 [ + ] → Minus decreases quantity
Quantity = 1: [ ] 1 [ + ] → Trash icon removes item

Visual Feedback: - Minus icon (quantity > 1) - Normal color

  • Trash icon (quantity = 1) - Red error color
  • Clear indication that tapping will remove the product

No need for separate delete button or swipe gestures!### Payment Method Logos

Payment providers are shown with official brand logos:


[Stripe Logo] Credit Card ← Professional
[Klarna Logo] Pay with Klarna brand recognition
[Vipps Logo] Vipps

Logos are:

  • Bundled with the SDK (no manual setup)
  • Displayed on white background cards
  • Fallback to SF Symbols if logo missing
  • Professional, trustworthy appearance

Price Display

Tax-Inclusive Pricing

The SDK displays prices with taxes(what customers actually pay):

// SDK automatically uses:
price.amountInclTaxes ?? price.amount

// What customers see:
Product: NOK 1,198.80With taxes
Cart Total: NOK 1,198.80Matches!

Price fields used: - amount - Base price (calculations)

  • amountInclTaxes - Displayed to users - taxAmount - Tax breakdown
  • compareAt - Original price before discount
  • compareAtInclTaxes - Original with taxes****Benefits: - No surprises at checkout
  • European pricing standard (VAT included)
  • Consistent across all views
  • Cart total matches product prices
  • Transparent pricing

Payment Security

PCI Compliance

The SDK is PCI DSS compliantbecause:

  • No card data storage - Stripe handles all sensitive data
  • Tokenization - Card info converted to secure tokens
  • HTTPS only - All communication encrypted
  • SCA compliance - 3D Secure built-in

Best Practices

// Good: Let the SDK handle Stripe initialization
init() {
ConfigurationLoader.loadConfiguration() // Automatic!
}

// Good: Specify payment methods in reachu-config.json
{
"cart": {
"supportedPaymentMethods": ["stripe", "klarna"]
}
}

// Good: SDK fetches keys from Reachu API (secure!)
// - Production keys come from Reachu backend
// - Test keys used automatically in sandbox mode
// - No keys in your code or config files

// Bad: Manual Stripe initialization (no longer needed!)
// import StripeCore
// StripeAPI.defaultPublishableKey = "pk_test_..." // DON'T DO THIS

Security

The SDK fetches payment provider keys from your Reachu backend, not from your app config. This means:

  • Keys never committed to version control
  • Keys can be rotated without app updates
  • Different keys for dev/staging/production
  • Centralized key management

Error Handling

Stripe Errors

do {
let paymentSheet = try await initializeStripePaymentSheet()
// Present payment sheet
} catch {
if let stripeError = error as? StripeError {
switch stripeError {
case .cardDeclined:
showError("Card was declined")
case .insufficientFunds:
showError("Insufficient funds")
case .networkError:
showError("Network error, please try again")
default:
showError("Payment failed")
}
}
}

Klarna Errors

KlarnaWebView(startURL: klarnaURL) { result in
switch result {
case .success:
completeOrder()
case .canceled:
// User canceled, cart still intact
showMessage("Payment canceled")
case .error(let error):
showError("Klarna payment failed: \(error.localizedDescription)")
}
}

Testing

Stripe Test Cards

Use these test cards in development:

Success:
4242 4242 4242 4242 (Visa)
5555 5555 5555 4444 (Mastercard)

Decline:
4000 0000 0000 0002 (Generic decline)

3D Secure:
4000 0025 0000 3155 (Requires authentication)

All test cards:
- Any future expiry date (12/25, 01/26, etc.)
- Any 3-digit CVC
- Any postal code

Klarna Test Mode

Klarna provides test mode for development:

  • Use test credentials from Klarna dashboard
  • Test different payment scenarios
  • No real money charged

Platform Support

PlatformStripeKlarnaNotes
iOS 15.0+FullFullComplete payment integration
iPhoneAll models supported
iPadOptimized for tablet
iOS-First Approach

The SDK is built specifically for iOS to deliver the best mobile shopping experience. All payment methods are fully tested and optimized for iPhone and iPad.

Troubleshooting

Payment Methods Not Showing

**Problem:**Expected payment method doesn't appear in checkout

**Debug Steps:**1. Check logs for payment method loading:

 [Checkout] API returned X payment methods
[Checkout] API method: Stripe (normalized: stripe)
Added: stripe

  1. Verify method is enabled in Reachu dashboard(most common issue)
  2. Check network connectivity to Reachu API
  3. Verify ConfigurationLoader.loadConfiguration() is called
  4. iOS 15.0+ deployment target

Common causes: - Method disabled in Reachu backend → Won't appear (expected)

  • Network error → Falls back to config supportedPaymentMethods
  • Unknown method name → Check logs for "Unknown payment method" warning

Debug commands:

// Check what API returns:
let methods = try await sdk.payment.getAvailableMethods()
print("API methods: \(methods.map { $0.name })")

// Check what config has (fallback only):
print("Config fallback: \(ReachuConfiguration.shared.cartConfiguration.supportedPaymentMethods)")

Stripe Payment Sheet Not Showing

**Problem:**Stripe sheet doesn't open

**Solutions:**1. Check that StripePaymentSheet is added as dependency 2. Verify Stripe is enabled in Reachu dashboard 3. Check logs for " [Config] Stripe configured" message 4. Ensure payment method appears in checkout 5. Verify customer has selected Stripe before tapping "Initiate Payment"

Klarna WebView Issues

**Problem:**Klarna WebView blank or not loading

**Solutions:**1. Check Klarna client token is valid 2. Verify success/cancel URLs are configured 3. Ensure proper SSL certificate on backend 4. Check console for WebView errors

Payment Processing Stuck

**Problem:**Payment appears to process forever

**Solutions:**1. Check backend webhook configuration 2. Verify payment intent status on Stripe dashboard 3. Ensure proper error handling in checkout flow 4. Check network logs for failed requests

Next Steps


Production Checklist

Before going live:

  1. Switch to production Stripe keys
  2. Enable Klarna production mode
  3. Test with real payment methods
  4. Configure webhooks on backend
  5. Enable 3D Secure
  6. Test refund flow