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.
**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:
- Add Stripe SDK
dependencies: [
.package(url: "https://github.com/stripe/stripe-ios.git", from: "23.0.0")
]
- 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()
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:
{
"payment": {
"applePay": {
"merchantIdentifier": "merchant.com.yourapp"
}
}
}
Klarna Setup
- Klarna Account - Contact Klarna for merchant account
- Get your Client Token
- Configure in Reachu
{
"payment": {
"klarna": {
"clientToken": "YOUR_KLARNA_CLIENT_TOKEN"
}
}
}
Stripe Integration
Automatic Setup (Zero Configuration!)
The SDK initializes Stripe automaticallywhen you call ConfigurationLoader.loadConfiguration():
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:
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
- User Reviews Cart →
RCheckoutOverlayshows order summary - Enters Shipping Address →
CheckoutDraftnormalizes data - Selects Stripe Payment → SDK initializes Payment Sheet
- Completes Payment → Stripe processes securely
- 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:
{
"cart": {
"enableGuestCheckout": true,
"requirePhoneNumber": true,
"defaultShippingCountry": "US",
"supportedPaymentMethods": ["stripe", "klarna", "vipps", "paypal"]
}
}
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:
// 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
- User Selects Klarna → SDK requests payment session
- Klarna WebView Opens → User logs in to Klarna
- Selects Payment Plan → "Pay in 3" or "Pay in 30 days"
- Authorizes Payment → Klarna approves transaction
- 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
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.80 ← With taxes
Cart Total: NOK 1,198.80 ← Matches!
Price fields used: - amount - Base price (calculations)
amountInclTaxes- Displayed to users -taxAmount- Tax breakdowncompareAt- Original price before discountcompareAtInclTaxes- 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
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
| Platform | Stripe | Klarna | Notes |
|---|---|---|---|
| iOS 15.0+ | Full | Full | Complete payment integration |
| iPhone | All models supported | ||
| iPad | Optimized for tablet |
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
- Verify method is enabled in Reachu dashboard(most common issue)
- Check network connectivity to Reachu API
- Verify
ConfigurationLoader.loadConfiguration()is called - 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
- CartManager - Global cart management
- CheckoutDraft - Address normalization
- RCheckoutOverlay - Complete checkout UI
Before going live:
- Switch to production Stripe keys
- Enable Klarna production mode
- Test with real payment methods
- Configure webhooks on backend
- Enable 3D Secure
- Test refund flow