react-native-datman-checkout-sdk
v0.1.9
Published
Razorpay-like checkout with hidden Swift UI via .xcframework (iOS)
Maintainers
Readme
Datman Checkout SDK for React Native
A sleek, privacy-first iOS checkout experience for React Native.
Minimal JS surface. Beautiful SwiftUI sheets. All payment logic sealed inside a native.xcframework.
✨ Why this SDK
- Drop-in UI: polished “New card” & “Saved cards” flows via native SwiftUI sheets.
- Tiny API surface:
init,presentNewCard,presentSavedCard. - Sealed native core: network + validation + UI live in a vendored
.xcframework—your app only sees a slim bridge. - Themeable: brand color + logo.
- Type-safe: first-class TypeScript types.
ℹ️ iOS supported today. Android can be added with a matching Kotlin
.aar+ RN bridge.
🚀 Install
# in your React Native app
npm i react-native-datman-checkout-sdk
# or
yarn add react-native-datman-checkout-sdk
# iOS pods
npx pod-installIf autolinking is restricted in your workspace, add this to your ios/Podfile (inside your app target):
pod 'RNDatmanCheckoutSDK', :path => '../node_modules/react-native-datman-checkout-sdk'Then pod install again.
Make sure your iOS app target has Other Linker Flags:
$(inherited)and-ObjC.
🧩 Quick start
// App.tsx
import { useEffect } from 'react';
import { Alert, Button, SafeAreaView, View } from 'react-native';
import {
init,
presentNewCard,
presentSavedCard,
} from 'react-native-datman-checkout-sdk';
export default function App() {
useEffect(() => {
init({
merchantId: 'YOUR_MERCHANT_ID',
publicKey: 'YOUR_PUBLIC_KEY',
environment: 'prod',
baseUrl: 'https://ws10-payments.datmanpay.com/earth/api/v1',
theme: { brandColor: '#0A84FF', logoUrl: 'https://placehold.co/64x64' },
}).catch(e => Alert.alert('Init failed', String(e)));
}, []);
const payNew = async () => {
const res = await presentNewCard({
amount: 1299, // minor units; 12.99 => 1299
currency: 'GBP',
orderId: `ORDER-\${Date.now()}`,
customer: { name: 'John Smith', email: '[email protected]', phone: '+44…' },
});
Alert.alert('Result', JSON.stringify(res, null, 2));
};
const paySaved = async () => {
const res = await presentSavedCard({
amount: 2599,
currency: 'GBP',
orderId: `ORDER-\${Date.now()}`,
savedCards: [
{ token: 'tok_abc', last4: '4242', brand: 'visa', expMonth: 12, expYear: 2028, label: 'Work' },
],
});
Alert.alert('Result', JSON.stringify(res, null, 2));
};
return (
<SafeAreaView>
<View style={{ padding: 24 }}>
<Button title="Pay with New Card" onPress={payNew} />
<View style={{ height: 12 }} />
<Button title="Pay with Saved Card" onPress={paySaved} />
</View>
</SafeAreaView>
);
}🛠 API
init(config) => Promise<boolean>
Initialize once (ideally on app boot).
type InitConfig = {
merchantId: string;
publicKey: string; // or token, per your backend
environment?: 'prod' | 'sandbox';
baseUrl?: string; // defaults to Datman prod base
theme?: { brandColor?: string; logoUrl?: string };
};presentNewCard(amount) => Promise<Result>
Presents the native “New card” sheet.
type Amount = {
amount: number; // minor units (e.g., 12.99 => 1299)
currency: string; // e.g., 'GBP'
orderId: string;
customer?: { name?: string; email?: string; phone?: string };
};presentSavedCard({ ...amount, savedCards }) => Promise<Result>
Presents the native “Saved cards” list + CVV prompt.
type SavedCard = {
token: string;
last4: string;
brand: string; // 'visa' | 'mastercard' | etc.
expMonth: number;
expYear: number;
label?: string;
};Common return type
type Result = {
status: 'success' | 'failed' | 'cancelled';
saleId?: string;
reference?: string;
message?: string;
raw?: any; // full gateway JSON (for diagnostics)
};🎨 UI & theming
- Brand color tints primary buttons.
- Logo URL appears in the payment header (square recommended, ~28px height).
- Light/Dark mode follows the host app.
All screens are powered by SwiftUI and presented via a sheet for a native feel.
🔒 Security notes
- PAN/CVV are handled exclusively within native code and sent directly to your gateway.
- No sensitive fields are logged or stored by the JS layer.
- If your processor requires 3-D Secure, you can extend the native core to launch the challenge flow before resolving the Promise.
📦 What ships in this package?
ios/RNPayCore.xcframework– the sealed native core (UI + network + validation).- Tiny RN bridge –
RNDatmanCheckoutnative module (Swift + Obj-C shim). - TypeScript surface – just three functions.
🧪 Requirements
- iOS 13.0+
- React Native ≥ 0.71
- CocoaPods
- Bare workflow (or EAS with a config plugin; managed workflow isn’t supported out of the box)
🩹 Troubleshooting
“Native module not found”
- Run
npx pod-install. - Open the .xcworkspace (not the .xcodeproj).
- Check
Podfile.lockcontainsRNDatmanCheckoutSDK. - Ensure your app target has Other Linker Flags:
-ObjC. - If needed, add to
Podfile:pod 'RNDatmanCheckoutSDK', :path => '../node_modules/react-native-datman-checkout-sdk'
Simulator crash: “calling into SwiftUI on a non-main thread”
- Update to the latest SDK. UI presentation is forced to the main thread in the bridge and marked
@MainActorin the native core.
Linker / module header warnings
- Harmless for pure Swift frameworks; the podspec already enables
DEFINES_MODULE. - Built with
BUILD_LIBRARY_FOR_DISTRIBUTION=YESfor ABI stability.
📍 Roadmap
- Android parity (native Kotlin UI +
.aar) - Config plugin for Expo/EAS
- 3-D Secure challenge flow
- Additional themes & localization hooks
📄 License
MIT © Datman
💬 Support
Found an issue or have a feature request? Open an issue in your repo, or drop a note in your project’s support channel. Happy building! 🚀
