Expo SDK
Official Expo SDK for PayGate - Accept Mobile Money payments with WebView or Browser mode.
Expo SDK
The official Expo SDK for PayGate enables you to accept Mobile Money payments in your Expo app with two modes: WebView (embedded) or Browser (system browser).
Requirements: Expo SDK 49+, react-native-webview. Optional: expo-web-browser for browser mode.
Features
- WebView Mode: Embedded checkout in a modal (default)
- Browser Mode: Open checkout in system browser (optional)
- Deep Linking: Return to app after browser checkout
Installation
npx expo install @paygate/expo react-native-webview
# Optional: For browser mode
npx expo install expo-web-browser expo-linkingQuick Start
Wrap your app with PayGateProvider
import { PayGateProvider, PayGateAutoModal } from '@paygate/expo'
export default function App() {
return (
<PayGateProvider
publicKey="pk_test_your_public_key"
baseUrl="https://paygate.com"
urlScheme="myapp" // Required for browser mode
>
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
<PayGateAutoModal />
</PayGateProvider>
)
}Trigger payments
import { usePayGate } from '@paygate/expo'
import { Button, Alert, View } from 'react-native'
function CheckoutScreen() {
const { checkout, openCheckoutInBrowser, browserAvailable, isVisible } = usePayGate()
const handlePayWithWebView = async () => {
const { sessionId } = await api.createCheckoutSession()
checkout({
sessionId,
onSuccess: (data) => {
Alert.alert('Success', 'Payment completed!')
},
onCancel: () => {
console.log('Cancelled')
},
})
}
const handlePayWithBrowser = async () => {
const { sessionId } = await api.createCheckoutSession()
await openCheckoutInBrowser({
sessionId,
onSuccess: (data) => {
Alert.alert('Success', 'Payment completed!')
},
})
}
return (
<View style={{ padding: 20 }}>
<Button
title="Pay with WebView"
onPress={handlePayWithWebView}
disabled={isVisible}
/>
{browserAvailable && (
<Button
title="Pay with Browser"
onPress={handlePayWithBrowser}
/>
)}
</View>
)
}Components
PayGateProvider
<PayGateProvider
publicKey="pk_test_xxx" // Required
baseUrl="https://paygate.com" // Optional
urlScheme="myapp" // Required for browser mode
defaultMode="webview" // 'webview' | 'browser'
>
{children}
</PayGateProvider>| Prop | Type | Required | Description |
|---|---|---|---|
publicKey | string | Yes | Your PayGate public key |
baseUrl | string | No | Base URL for checkout pages |
urlScheme | string | No* | URL scheme for deep linking (*required for browser mode) |
defaultMode | string | No | Default payment mode |
PayGateAutoModal
Auto-managed modal that responds to checkout() and payWithLink() calls.
<PayGateAutoModal />PayGateModal
Manually controlled modal.
<PayGateModal
visible={visible}
sessionId="cs_xxx"
onSuccess={(data) => {}}
onCancel={() => {}}
onClose={() => setVisible(false)}
/>PayGate
Low-level WebView component.
<PayGate
sessionId="cs_xxx"
onSuccess={(data) => {}}
onCancel={() => {}}
onError={(error) => {}}
style={{ flex: 1 }}
/>Hooks
usePayGate
import { usePayGate } from '@paygate/expo'
const {
// WebView mode
checkout, // (params) => void
payWithLink, // (params) => void
// Browser mode
openCheckoutInBrowser, // (params) => Promise<void>
openPaymentLinkInBrowser, // (params) => Promise<void>
// State
close, // () => void
isVisible, // boolean
mode, // 'webview' | 'browser'
setMode, // (mode) => void
browserAvailable, // boolean
publicKey, // string
baseUrl, // string
} = usePayGate()Payment Modes
WebView Mode (Default)
Opens checkout in an embedded WebView modal. Best for most apps.
const { checkout } = usePayGate()
checkout({
sessionId: 'cs_xxx',
onSuccess: (data) => console.log('Paid!', data),
})Browser Mode
Opens checkout in system browser. Requires expo-web-browser and expo-linking.
const { openCheckoutInBrowser, browserAvailable } = usePayGate()
if (browserAvailable) {
await openCheckoutInBrowser({
sessionId: 'cs_xxx',
onSuccess: (data) => console.log('Paid!', data),
})
}Comparison
| Feature | WebView Mode | Browser Mode |
|---|---|---|
| User Experience | In-app modal | System browser |
| Setup | Simpler | Requires deep linking |
| Dependencies | react-native-webview | + expo-web-browser, expo-linking |
| Best for | Most apps | Apps needing browser features |
Payment Links
const { payWithLink, openPaymentLinkInBrowser } = usePayGate()
// WebView mode
payWithLink({
linkId: 'pl_xxx',
amount: 50.00, // For dynamic amount
email: 'customer@example.com',
onSuccess: (data) => console.log('Paid!', data),
})
// Browser mode
await openPaymentLinkInBrowser({
linkId: 'pl_xxx',
amount: 50.00,
onSuccess: (data) => console.log('Paid!', data),
})TypeScript
import type {
PayGateConfig,
CheckoutParams,
PaymentLinkParams,
PaymentResult,
PayGateError,
PaymentMode,
} from '@paygate/expo'Test Mode
Use test keys (pk_test_xxx) during development:
<PayGateProvider publicKey="pk_test_xxx" urlScheme="myapp">
{/* Test mode enabled */}
</PayGateProvider>Complete Example
import React, { useState } from 'react'
import { View, Button, Text, StyleSheet, Alert } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { PayGateProvider, PayGateAutoModal, usePayGate } from '@paygate/expo'
const Stack = createNativeStackNavigator()
function CheckoutScreen() {
const { checkout, openCheckoutInBrowser, browserAvailable, isVisible } = usePayGate()
const [loading, setLoading] = useState(false)
const createSession = async () => {
const response = await fetch('https://api.yourstore.com/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 100 }),
})
return response.json()
}
const handleWebViewCheckout = async () => {
setLoading(true)
try {
const { sessionId } = await createSession()
checkout({
sessionId,
onSuccess: (data) => {
Alert.alert('Success', `Payment ${data.id} completed!`)
},
onCancel: () => {
Alert.alert('Cancelled', 'Payment was cancelled')
},
onError: (error) => {
Alert.alert('Error', error.message)
},
})
} catch (error) {
Alert.alert('Error', 'Failed to create session')
} finally {
setLoading(false)
}
}
const handleBrowserCheckout = async () => {
setLoading(true)
try {
const { sessionId } = await createSession()
await openCheckoutInBrowser({
sessionId,
onSuccess: (data) => {
Alert.alert('Success', 'Payment completed!')
},
onCancel: () => {
Alert.alert('Cancelled', 'Payment was cancelled')
},
})
} catch (error) {
Alert.alert('Error', 'Failed to open browser')
} finally {
setLoading(false)
}
}
return (
<View style={styles.container}>
<Text style={styles.title}>Checkout</Text>
<Text style={styles.price}>Total: GHS 100.00</Text>
<View style={styles.buttons}>
<Button
title={loading ? 'Loading...' : 'Pay with WebView'}
onPress={handleWebViewCheckout}
disabled={loading || isVisible}
/>
{browserAvailable && (
<View style={styles.buttonSpacing}>
<Button
title="Pay with Browser"
onPress={handleBrowserCheckout}
disabled={loading}
/>
</View>
)}
</View>
</View>
)
}
export default function App() {
return (
<PayGateProvider
publicKey="pk_test_xxx"
baseUrl="https://paygate.com"
urlScheme="myapp"
>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Checkout" component={CheckoutScreen} />
</Stack.Navigator>
</NavigationContainer>
<PayGateAutoModal />
</PayGateProvider>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 },
title: { fontSize: 24, fontWeight: 'bold', marginBottom: 10 },
price: { fontSize: 18, marginBottom: 30 },
buttons: { width: '100%' },
buttonSpacing: { marginTop: 10 },
})Troubleshooting
WebView not loading
npx expo install react-native-webviewBrowser mode not working
- Install dependencies:
npx expo install expo-web-browser expo-linking- Configure URL scheme in
app.json:
{
"expo": {
"scheme": "myapp"
}
}- Pass
urlSchemeto provider:
<PayGateProvider publicKey="..." urlScheme="myapp">Deep link not returning to app
Make sure your URL scheme matches in:
app.json→expo.schemePayGateProvider→urlSchemeprop
browserAvailable is false
Install the optional dependencies:
npx expo install expo-web-browser expo-linking