React Native SDK
The official PayKore SDK for React Native. Wraps the core @paykore/sdk with React-friendly patterns — a context provider and hooks — for building payment flows directly in your mobile app.
Installation
npm install @paykore/react-native-sdk
This package requires @paykore/sdk as a peer dependency. If it isn't already installed:
npm install @paykore/sdk @paykore/react-native-sdk
Setup — Provider
Wrap your app in PayKoreProvider once, near the root of your component tree:
import { PayKoreProvider } from '@paykore/react-native-sdk';
export default function App() {
return (
<PayKoreProvider apiKey={process.env.EXPO_PUBLIC_PAYKORE_KEY} environment="sandbox">
<YourApp />
</PayKoreProvider>
);
}
Every hook described below reads its configuration from this provider — you won't need to pass an API key or environment to each hook individually.
Only use publishable keys (pk_*) in mobile apps. Never embed secret keys (sk_*) in React Native code — anything bundled into your app, including environment variables prefixed for client exposure (like EXPO_PUBLIC_*), can be extracted from the compiled app binary by anyone who downloads it from the App Store or Play Store.
useWallet hook
const { wallet, balance, loading, error, refresh } = useWallet('wallet_id');
| Return value | Type | Description |
|---|---|---|
wallet | Wallet | null | The full wallet object once loaded. |
balance | { kobo: number; naira: string } | null | Convenience accessor for the wallet's current balance. |
loading | boolean | true while the initial fetch or a refresh() is in flight. |
error | PayKoreError | null | Populated if the fetch fails. |
refresh | () => Promise<void> | Re-fetches the wallet on demand. |
Complete example — balance display with refresh:
import { useWallet } from '@paykore/react-native-sdk';
import { View, Text, Button, ActivityIndicator } from 'react-native';
function WalletBalance({ walletId }: { walletId: string }) {
const { wallet, balance, loading, error, refresh } = useWallet(walletId);
if (loading && !wallet) return <ActivityIndicator />;
if (error) return <Text>Couldn't load wallet: {error.message}</Text>;
return (
<View>
<Text>Balance: ₦{balance?.naira}</Text>
<Button title="Refresh" onPress={refresh} disabled={loading} />
</View>
);
}
useTransfer hook
const { transfer, loading, error } = useTransfer();
// Usage:
await transfer.p2p({ sourceWallet, destWallet, amount, idempotencyKey });
transfer.p2p(...) triggers a P2P transfer and updates loading/error for the duration of the call, so you can drive a loading spinner or disabled button state directly from the hook without managing your own local state.
usePayment hook
const { createQRIntent, payQRIntent, initiateUSSD, loading, error } = usePayment();
This hook bundles the three non-transfer payment flows — QR intent creation, QR intent payment, and USSD initiation — behind one shared loading/error pair, since a given screen typically only triggers one of them at a time.
QR code payment component example
Mobile apps can't receive webhooks directly — there's no public URL for PayKore to push to. The standard pattern is: create the intent, render the QR, and poll for completion from the client while your backend's webhook handler is the source of truth server-side.
import { useState, useEffect } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import { usePayment, usePaymentStatus } from '@paykore/react-native-sdk';
function QRCheckout({ merchantWalletId, amountKobo, reference }: QRCheckoutProps) {
const { createQRIntent, loading, error } = usePayment();
const [intent, setIntent] = useState<QRIntent | null>(null);
useEffect(() => {
createQRIntent({ merchantWalletId, amountKobo, reference }).then(setIntent);
}, []);
// Polls the intent status every 2s until it resolves
const { status } = usePaymentStatus(intent?.intentId, { pollIntervalMs: 2000 });
if (loading || !intent) return <ActivityIndicator />;
if (error) return <Text>Couldn't create payment: {error.message}</Text>;
if (status === 'completed') {
return <Text>✅ Payment received!</Text>;
}
return (
<View>
<QRCode value={intent.qrPayload} size={240} />
<Text>Waiting for payment...</Text>
</View>
);
}
usePaymentStatus handles the polling loop internally and stops once the status reaches a terminal state (completed, failed, or expired), so you don't need to manually clear an interval.
Deep link handling for QR payments
When a user scans a PayKore QR code with their own wallet app (rather than your merchant app rendering the code), that wallet app needs a way to open and load the specific payment intent. This is handled via deep links.
Expo configuration (app.json):
{
"expo": {
"scheme": "yourapp",
"ios": {
"associatedDomains": ["applinks:yourapp.com"]
},
"android": {
"intentFilters": [
{
"action": "VIEW",
"data": [{ "scheme": "yourapp", "host": "pay" }],
"category": ["BROWSABLE", "DEFAULT"]
}
]
}
}
}
This registers yourapp://pay as a URL your app will handle. A scanned QR code that resolves to yourapp://pay?intentId=qri_4hJkL5mNpQ will open your app directly to the payment screen.
Handling the incoming intent ID:
import * as Linking from 'expo-linking';
import { useEffect } from 'react';
function usePaymentDeepLink(onIntentReceived: (intentId: string) => void) {
useEffect(() => {
const subscription = Linking.addEventListener('url', ({ url }) => {
const { queryParams } = Linking.parse(url);
if (queryParams?.intentId) {
onIntentReceived(queryParams.intentId as string);
}
});
return () => subscription.remove();
}, [onIntentReceived]);
}
Use the extracted intentId to call payQRIntent from the usePayment hook once the user confirms the amount on screen.
Error handling in hooks
Every hook's error value is typed as PayKoreError | null, the same error class used by the underlying @paykore/sdk:
import type { PayKoreError } from '@paykore/sdk';
const { wallet, error } = useWallet(walletId);
if (error) {
const typedError: PayKoreError = error;
console.log(typedError.code); // e.g. "WALLET_NOT_FOUND"
console.log(typedError.requestId); // for support escalation
}
Branch on error.code exactly as you would server-side — see Web SDK: Error handling for the full list of codes you may encounter.
Next steps
- Web SDK → — The underlying server-side SDK and full error code reference.
- QR Payments → — The full QR payment flow and payload structure.