React Native Integration ​
Production-Ready Integration Pattern
This guide shows battle-tested integration patterns for Bridge Payments in React Native apps, based on real production implementations.
Bridge Payments is a production-ready REST API that you integrate directly using fetch. Official React Native SDK coming soon!
Installation ​
bash
# Install Stripe React Native (required for payment UI)
npm install @stripe/stripe-react-native
# Install dependencies
npx pod-install # iOS onlyDirect API Integration
Bridge Payments is a REST API - no Bridge Payments-specific packages needed! Just use fetch to make HTTP requests to your Bridge Payments instance. This gives you complete control and flexibility.
Configuration ​
1. Environment Variables ​
Create or update your .env file:
bash
# Bridge Payments instance URL
EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL=https://your-instance.pubflow.com
# Stripe publishable key
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Optional: Enable debug logging
EXPO_PUBLIC_LOG_MODE=development2. Initialize Stripe Provider ​
tsx
// App.tsx
import { StripeProvider } from '@stripe/stripe-react-native';
export default function App() {
return (
<StripeProvider publishableKey={process.env.EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY!}>
{/* Your app content */}
</StripeProvider>
);
}Basic Usage ​
Create Payment Client ​
typescript
import { BridgePaymentClient } from '@pubflow/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
// Get session ID from AsyncStorage
const sessionId = await AsyncStorage.getItem('pubflow_session_id');
// Initialize client
const client = new BridgePaymentClient({
baseUrl: process.env.EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL!,
sessionId: sessionId!
});Complete Payment Flow ​
tsx
import { useState } from 'react';
import { View, Button, Alert } from 'react-native';
import { CardField, useStripe } from '@stripe/stripe-react-native';
import { BridgePaymentClient } from '@pubflow/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
function CheckoutScreen() {
const stripe = useStripe();
const [loading, setLoading] = useState(false);
const handlePayment = async () => {
setLoading(true);
try {
// 1. Get session ID
const sessionId = await AsyncStorage.getItem('pubflow_session_id');
// 2. Initialize client
const client = new BridgePaymentClient({
baseUrl: process.env.EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL!,
sessionId: sessionId!
});
// 3. Create payment intent
const intent = await client.createPaymentIntent({
subtotal_cents: 1800,
tax_cents: 200,
total_cents: 2000,
currency: 'USD',
concept: 'Premium Subscription',
description: 'Monthly premium plan',
provider_id: 'stripe'
});
// 4. Confirm payment with Stripe
const { error, paymentIntent } = await stripe.confirmPayment(
intent.client_secret,
{
paymentMethodType: 'Card'
}
);
if (error) {
Alert.alert('Payment Failed', error.message);
return;
}
// 5. Sync status with backend
const payment = await client.syncPaymentStatus(paymentIntent.id);
if (payment.status === 'succeeded') {
Alert.alert('Success', 'Payment completed successfully!');
}
} catch (error) {
console.error('Payment error:', error);
Alert.alert('Error', 'An error occurred. Please try again.');
} finally {
setLoading(false);
}
};
return (
<View style={{ padding: 20 }}>
<CardField
postalCodeEnabled={false}
style={{ height: 50, marginBottom: 20 }}
/>
<Button
title={loading ? 'Processing...' : 'Pay $20.00'}
onPress={handlePayment}
disabled={loading}
/>
</View>
);
}Payment Methods ​
List Saved Payment Methods ​
typescript
const client = new BridgePaymentClient({
baseUrl: process.env.EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL!,
sessionId: sessionId!
});
const methods = await client.getPaymentMethods();
// Display payment methods
methods.forEach(method => {
console.log(`${method.card_brand} ending in ${method.card_last_four}`);
});Save Payment Method During Payment ​
typescript
const intent = await client.createPaymentIntent({
total_cents: 2000,
currency: 'USD',
concept: 'First Purchase',
setup_future_usage: 'off_session' // Save for future use
});Use Saved Payment Method ​
typescript
const intent = await client.createPaymentIntent({
total_cents: 2000,
currency: 'USD',
concept: 'Subscription Renewal',
payment_method_id: savedMethod.id // Use saved method
});Delete Payment Method ​
typescript
await client.deletePaymentMethod(methodId);Guest Checkout ​
tsx
function GuestDonationScreen() {
const stripe = useStripe();
const [email, setEmail] = useState('');
const [name, setName] = useState('');
const [amount, setAmount] = useState(50);
const handleDonation = async () => {
try {
// No session ID required for guest checkout
const client = new BridgePaymentClient({
baseUrl: process.env.EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL!
});
const intent = await client.createPaymentIntent({
total_cents: amount * 100,
currency: 'USD',
concept: 'Donation',
provider_id: 'stripe',
guest_data: {
email,
name
}
});
const { error } = await stripe.confirmPayment(
intent.client_secret,
{
paymentMethodType: 'Card'
}
);
if (!error) {
Alert.alert('Thank You!', 'Your donation was successful.');
}
} catch (error) {
console.error('Donation error:', error);
}
};
return (
<View style={{ padding: 20 }}>
<TextInput
placeholder="Email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
/>
<TextInput
placeholder="Name"
value={name}
onChangeText={setName}
/>
<TextInput
placeholder="Amount"
value={String(amount)}
onChangeText={(text) => setAmount(Number(text))}
keyboardType="numeric"
/>
<CardField style={{ height: 50, marginVertical: 20 }} />
<Button title={`Donate $${amount}`} onPress={handleDonation} />
</View>
);
}Addresses ​
Create Address ​
typescript
const address = await client.createAddress({
line1: '123 Main St',
line2: 'Apt 4B',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
});List Addresses ​
typescript
const addresses = await client.getAddresses();Update Address ​
typescript
await client.updateAddress(addressId, {
line1: '456 Oak Ave'
});Delete Address ​
typescript
await client.deleteAddress(addressId);Subscriptions ​
Create Subscription ​
typescript
const subscription = await client.createSubscription({
product_id: 'prod_premium',
payment_method_id: savedMethodId,
trial_days: 14,
concept: 'Premium Monthly Plan'
});List Subscriptions ​
typescript
const subscriptions = await client.getSubscriptions();Cancel Subscription ​
typescript
await client.cancelSubscription(subscriptionId);Error Handling ​
typescript
try {
const intent = await client.createPaymentIntent({
total_cents: 2000,
currency: 'USD'
});
} catch (error) {
if (error.response?.status === 401) {
// Session expired, redirect to login
navigation.navigate('Login');
} else if (error.response?.status === 400) {
// Validation error
Alert.alert('Error', error.response.data.message);
} else {
// Network or server error
Alert.alert('Error', 'An unexpected error occurred');
}
}Caching & Performance ​
The client automatically caches responses for better performance:
typescript
// Configure cache
const client = new BridgePaymentClient({
baseUrl: process.env.EXPO_PUBLIC_BRIDGE_BASE_PAYMENT_URL!,
sessionId: sessionId!,
cache: {
enabled: true,
ttl: 300000 // 5 minutes
}
});
// Force refresh (bypass cache)
const methods = await client.getPaymentMethods({ forceRefresh: true });TypeScript Support ​
Full TypeScript support with type definitions:
typescript
import type {
PaymentIntent,
PaymentMethod,
Address,
Subscription,
CreatePaymentIntentRequest
} from '@pubflow/react-native';
const request: CreatePaymentIntentRequest = {
total_cents: 2000,
currency: 'USD',
concept: 'Premium Plan'
};
const intent: PaymentIntent = await client.createPaymentIntent(request);Next Steps ​
- Next.js Client - Next.js integration
- API Reference - Complete API documentation
- Guest Checkout Guide - Implement guest payments
- Testing - Test your integration